It's your class - you know where you're putting it.
If you're not sharing it, then just pick an ID below 0xBFFF and be done with it.
If your class belongs in a DLL that can be shared by multiple applications... Or can simply be shared by code that you don't control and therefore are unable to sort out IDs for... then use GlobalAddAtom()
to get an ID (and remember to call GlobalDeleteAtom()
after you unregister the hotkey).
Explanation
It's probably worth taking a minute to think about why there are two different ID ranges, and why the API docs recommend using GlobalAddAtom()
to obtain an ID in the latter range for shared DLLs. Let's start with the documentation for the parameter to RegisterHotKey()
:
id
[in] Specifies the identifier of the hot key. If the hWnd parameter is NULL, then the hot key is associated with the current thread rather than with a particular window. If a hot key already exists with the same hWnd and id parameters, see Remarks for the action taken.
From this, we can surmise that hotkeys are uniquely identified by one of two potential pairs of information: a thread or window handle, and an arbitrary 16-bit number. If you specify a window handle (HWND
), then the message is sent to that window; otherwise, it's sent to the thread.
So... If you only register one hotkey for a given window, the ID doesn't really matter1; no one else can register a hotkey for that window, and hotkey events for other windows will post to those windows. Similarly, if you only register one windowless hotkey for a given thread, you'll only get messages for that hotkey. If you control all of the code for your application, you can pick whatever IDs you want for your hotkeys, using whatever technique you want to assign them; no one else will step on them, because you own all the code that would be able to step on them!
But what if you're writing a general-purpose routine that can be called by other code? You can't reliably pick a constant ID then, since the caller could potentially be using that ID already, and if they're also using the same window or thread, you'd end up redefining their hotkey. Or what if (as in your case) you don't know how many hotkeys will be registered until runtime?
You need a way to ensure that the ID you choose at runtime will be one that no one else is using. This is where GlobalAddAtom()
comes into play: you pass it a string, and it gives you an ID guaranteed to correspond to that string and no other; this is effectively unique for the system, unless someone else passes the same string - and you can probably come up with a unique string; just use your company name, or your social security number, and a prefix that you increment for each new atom that you need. Or, if you're really paranoid, use a GUID.
The truth behind truths
With that out of the way, let me try to clear up a bit of confusion: Windows doesn't actually care whether or not the code that calls RegisterHotKey()
is in a DLL. It can't. Consider the following routine:
void RegisterSuperHappyFunHotKey(HWND hWnd, int id,
unsigned int fsModifiers, unsigned int vk)
{
RegisterHotKey(hWnd, id, fsModifiers, vk);
}
This routine does nothing but forward its parameters on to the WinAPI function, none of which identify the calling module. If it lived in a DLL, it would behave the same as if it was compiled into the application itself. There's no reliable way for Windows to tell where the call originates, and the hotkey itself is tied to a window and thread (or a thread alone) either of which could be controlled by code in or out of a DLL. Now of course, you could have app- or library-specific requirements of your own: if your DLL creates a window and sets up a hotkey for it, then you'll want to take care of unregistering that hotkey when you destroy the window... But that's your own concern, to handle as you see fit.
MSDN specifies the two ranges of IDs for one good reason: to encourage you, the DLL author, to avoid stepping on IDs used by an application author. If you're the application author, then the world is your oyster - you control (for the most part) which code gets loaded and executed in your application's process, and can therefore make the decisions as to which IDs you use however you see fit: starting at 0 and incrementing for each new hotkey is perfectly acceptable. But once you venture into the upper range of IDs, you'll have to use GlobalAddAtom()
just as if you were a DLL - or you run the risk of colliding with an ID generated in this manner by third-party code loaded from a DLL. It's a... social contract of sorts.
Summary:
The "shared DLL" bit is a red herring here; if you can know the IDs of all hotkeys registered by your application, then just pick a number below 0xBFFF and use it. If you can't, because your code will be used by multiple callers (as yours is...), then obtain an ID using GlobalAddAtom()
and use that.
Recommendation
For these reasons, I recommend that you do use GlobalAddAtom()
for the class you're designing, simply because it sounds as though you don't know at this time whether or not you'll be building it into an application of your own design (where you control the IDs being used) or a DLL to be loaded by some other app (where you do not). Don't worry - you're not violating the contract by pretending to be a DLL, so long as you follow the rules set forth for DLL callers.
1ok, so there are a couple of system-defined hotkey IDs that you have to watch out for...