How to programmatically determine if code works in a shared DLL or exe?

A has a C # class that simplifies the handling of global hot keys. This class uses the Win32-API RegisterHotKey() function to register hotkeys.

According to MSDN, this function requires an ID value in the range 0x0000 to 0xBFFF when calling from the application and an identifier value in the range 0xC000 to 0xFFFF when calling from the common DLL. GlobalAddAtom() can be used to get the identifier in case of launch in the DLL.

To hide this difference from the class user, the class itself must decide which ID number to use when registering the hotkey. Well, for that, the class should be able to determine if its code is working in the application or inside the common DLL.

But how to do that? What is the best C # /. NET way to do this?

+4
source share
3 answers

Try the following:

 bool isDll = this.GetType().Assembly.EntryPoint == null; 

MSDN:

Assembly.EntryPoint Property

"The value of the property is the MethodInfo object that represents the entry point of this assembly. If there is no entry point (for example, the assembly is a DLL), a null reference (Nothing in Visual Basic)."

+3
source

He is your class - you know where you put him.

If you don’t share it, just select the identifier below 0xBFFF and do with it.

If your class belongs to a DLL that can be used by several applications ... Or it can just be split using code that you do not control, and therefore cannot sort the identifiers for ... then use GlobalAddAtom() to get the identifier (and don't forget to call GlobalDeleteAtom() after unregister the hotkey ).


Explanation

It's probably worth considering why there are two different ranges of identifiers, and why API documents recommend using GlobalAddAtom() to get the identifier in the last range for shared DLLs. Start with the documentation for the RegisterHotKey() parameter:

ID
[in] Specifies the hotkey identifier. If the hWnd parameter is NULL, then the hotkey is associated with the current thread, and not with a specific window. If a hotkey already exists with the same hWnd and id parameters, see Notes for action taken.

From this it can be assumed that hot keys are uniquely identified by one of two potential pairs of information: a stream or window handle and an arbitrary 16-bit number. If you specify a window handle ( HWND ), a message will be sent to this window; otherwise, it is sent to the stream.

So ... If you only register one hotkey for this window, then the identifier does not really matter 1 ; no one else can register a hotkey for this window, and hotkey events for other windows will be placed in these windows. Similarly, if you register only one windowless hotkey for a given stream, you will receive only messages for this hotkey. If you control all the code for your application, you can choose any identifiers that you want for your hot keys using any technique you want to assign; nobody will step on them, because you own all the code that can step on them!

But what if you write a universal procedure that can be called with other code? You cannot reliably select a persistent identifier, since the caller can potentially use this identifier already, and if they also use the same window or stream, you will eventually override their hotkey. Or what if (as in your case) you do not know how many hotkeys will be registered before execution?

You need a way to make sure that the identifier you select at run time is one that no one else uses. GlobalAddAtom() used GlobalAddAtom() : you pass it a string and it gives you an ID that matches that string, and no other; this is truly unique to the system, unless someone else passes the same line - and you can probably come up with a unique line; just use your company name or your social security number and the prefix that you increase for every new atom that you need. Or, if you are really paranoid, use a GUID.

Truth truth

Because of this, let me try to clear up the confusion: Windows really doesn't care if the code that calls RegisterHotKey() is in the DLL. It's impossible. Consider the following procedure:

 void RegisterSuperHappyFunHotKey(HWND hWnd, int id, unsigned int fsModifiers, unsigned int vk) { RegisterHotKey(hWnd, id, fsModifiers, vk); } 

This routine does nothing except send its parameters to the WinAPI function, none of which identify the calling module. If he lives in a DLL, he will behave as if he had been compiled in the application itself. There is no reliable way for Windows to indicate where the call comes from, and the hotkey itself is bound to a window and a thread (or a single thread) that can be controlled by code in or from a DLL. Now, of course, you can have your own requirements for applications or libraries: if your DLL creates a window and sets a hot key for it, you will want to take care to cancel this hot key when you destroy the window ... But this is your own care to cope on your own.

MSDN specifies two ranges of identifiers for one good reason: recommend that you, the author of the DLL, avoid typing the identifiers used by the author of the application. If you are the author of the application, then the world - your oyster - you control (for the most part) which code is downloaded and executed in the process of your application, and therefore can make decisions about which identifiers you use: starting from 0 and increments for each The new hotkey is quite acceptable. But as soon as you fall into the upper range of identifiers, you will have to use GlobalAddAtom() in the same way as if you were a DLL, or you run the risk of encountering an identifier generated in this way by third-party code loaded from a DLL. This is ... a social contract .

Summary:

The bit "shared DLL" is a red herring; if you can find out the identifiers of all the hot keys registered by your application, just select the number below 0xBFFF and use it. If you cannot, because your code will be used by several subscribers (like yours ...), then get the identifier using GlobalAddAtom() and use it.

Recommendation

For these reasons, I recommend that you do GlobalAddAtom() for the class you are developing, simply because it sounds like you currently do not know (in case you control the identifiers used) or the DLL to load to others application (where you are not ). Do not worry - you do not break the contract by pretending to be a DLL if you follow the rules set for calling DLLs.


1 ok, so there are several system hotkey identifiers that you must follow ...

+3
source

Completing Philippe's answer:

You need to get a link to the assembly that calls your function, so the code should look like this:

 Assembly assembly = Assembly.GetCallingAssembly(); Boolean isDll = assembly.EntryPoint == null; 

Hope this helps.

Ricardo Lacerda Castelo Branco

+1
source

All Articles