如何以编程方式检测代码是在共享DLL还是exe中运行?
-
06-07-2019 - |
题
A有一个C#类,简化了全局热键的处理。
该类使用Win32-API函数 RegisterHotKey()
来注册热键。
根据MSDN,此函数需要ID值在0x0000到0xBFFF范围内
从应用程序调用时,ID值在0xC000到0xFFFF范围内
从共享DLL调用。 GlobalAddAtom()
可用于在运行时获取ID
在DLL中。
要隐藏与类用户的区别,类本身应该决定哪个 注册热键时使用ID范围。好吧,要做到这一点,班级必须 能够检测其代码是在应用程序内还是在应用程序内运行 共享DLL。
但是怎么做?什么是最好的C#/ .NET方式呢?
解决方案
试试这个:
bool isDll = this.GetType().Assembly.EntryPoint == null;
MSDN:
"属性值MethodInfo对象 这代表了入口点 这个集会。如果没有入口点 发现(例如,组件是一个 DLL),一个空引用(Nothing in 返回Visual Basic)。 "
其他提示
你的类 - 你知道你把它放在哪里。
如果您没有共享它,那么只需选择一个低于0xBFFF的ID并完成它。
如果您的类属于可以由多个应用程序共享的DLL ...或者可以简单地由您无法控制的代码共享,因此无法为...分类ID,然后使用 GlobalAddAtom()
获取ID(并记住你之后打电话给 GlobalDeleteAtom()
取消注册热键)。
解释
考虑为什么存在两个不同的ID范围,以及为什么API文档建议使用 GlobalAddAtom()
来获取共享DLL的后一范围内的ID,这可能值得花一点时间。让我们从 RegisterHotKey()
的参数文档开始:
ID 结果     [in]指定热键的标识符。如果hWnd参数为NULL,则热键与当前线程关联,而不是与特定窗口关联。如果已存在具有相同hWnd和id参数的热键,请参阅所执行操作的备注。
由此我们可以推测,热键由两个可能的信息对中的一个唯一标识:线程或窗口句柄,以及任意16位数字。如果指定窗口句柄( HWND
),则消息被发送到该窗口;否则,它被发送到线程。
所以......如果你只为给定的窗口注册一个热键,那么这个ID并不重要 1 ;没有其他人可以为该窗口注册热键,其他窗口的热键事件将发布到这些窗口。同样,如果您只为给定的线程注册一个无窗口热键,您将只获取该热键的消息。 如果您控制应用程序的所有代码,您可以使用您想要分配它们的任何技术来选择您想要的热键ID ;没有其他人会踩到他们,因为你拥有能够的所有代码来踩他们!
但是如果你正在编写一个可以被其他代码调用的通用例程呢?您无法可靠地选择常量ID,因为调用者可能已经使用该ID,如果他们也使用相同的窗口或线程,您最终将重新定义其热键。或者,如果(在您的情况下)您不知道在运行时将注册多少热键?
您需要一种方法来确保您在运行时选择的ID将是其他人无法使用的ID。这是 GlobalAddAtom()
发挥作用的地方:你传递一个字符串,它给你一个保证与该字符串相对应的ID而不是其他字符串;这对系统来说实际上是唯一的,除非其他人传递相同的字符串 - 你可能会想出一个独特的字符串;只需使用您的公司名称或社会安全号码,以及为您需要的每个新原子增加的前缀。或者,如果你真的是偏执狂,请使用GUID。
真相背后的真相
有了这个,让我试着澄清一些混乱:Windows实际上并不关心调用 RegisterHotKey()
的代码是否在DLL中。它不能。请考虑以下例程:
void RegisterSuperHappyFunHotKey(HWND hWnd, int id,
unsigned int fsModifiers, unsigned int vk)
{
RegisterHotKey(hWnd, id, fsModifiers, vk);
}
此例程 nothing 但将其参数转发到WinAPI函数,其中没有一个标识调用
完成菲利普回答:
您需要获取调用函数的程序集的引用,因此代码应如下所示:
Assembly assembly = Assembly.GetCallingAssembly();
Boolean isDll = assembly.EntryPoint == null;
希望这有帮助。
Ricardo Lacerda Castelo Branco