C# 如何以编程方式检测代码是否在共享DLL或exe中运行?
A有一个C#类,它简化了全局热键的处理。 此类使用Win32 API函数C# 如何以编程方式检测代码是否在共享DLL或exe中运行?,c#,.net,winapi,dll,registerhotkey,C#,.net,Winapi,Dll,Registerhotkey,A有一个C#类,它简化了全局热键的处理。 此类使用Win32 API函数RegisterHotKey()来注册热键 根据MSDN,当 当发生以下情况时,从应用程序和0xC000到0xFFFF范围内的ID值调用 从共享DLL调用GlobalAddAtom()可用于在运行时获取ID 在DLL中 为了向类的用户隐藏这种区别,类本身应该决定哪一个 注册热键时要使用ID范围。要做到这一点,全班必须 能够检测其代码是在应用程序中运行还是在 共享DLL 但如何做到这一点呢?C#/.NET最好的方法是什么?试试
RegisterHotKey()
来注册热键
根据MSDN,当
当发生以下情况时,从应用程序和0xC000到0xFFFF范围内的ID值调用
从共享DLL调用GlobalAddAtom()
可用于在运行时获取ID
在DLL中
为了向类的用户隐藏这种区别,类本身应该决定哪一个
注册热键时要使用ID范围。要做到这一点,全班必须
能够检测其代码是在应用程序中运行还是在
共享DLL
但如何做到这一点呢?C#/.NET最好的方法是什么?试试这个:
bool isDll = this.GetType().Assembly.EntryPoint == null;
MSDN:
“MethodInfo对象的属性值”
它代表了
此程序集。如果未指定入口点
已找到(例如,程序集是
DLL),一个空引用(在
返回“Visual Basic”
这是你的班级-你知道你把它放在哪里 如果您不共享它,那么只需在0xBFFF下面选择一个ID,就可以使用它了 如果您的类属于可由多个应用程序共享的DLL。。。或者可以由您无法控制的代码共享,因此无法为。。。然后使用获取ID(并记住在您之后打电话)
解释 可能值得花一分钟时间思考一下为什么有两个不同的ID范围,以及为什么API文档建议使用
GlobalAddAtom()
为共享DLL获取后一个范围内的ID。让我们从RegisterHotKey()参数的文档开始:
id
[in]指定热键的标识符。如果hWnd参数为NULL,则热键与当前线程关联,而不是与特定窗口关联。如果已经存在具有相同hWnd和id参数的热键,请参阅备注了解所采取的操作
由此,我们可以推测热键是由两对潜在信息中的一对唯一标识的:线程或窗口句柄和任意16位数字。如果指定一个窗口句柄(HWND
),则发送到该窗口;否则,它将被发送到线程
所以。。。如果只为给定窗口注册一个热键,则ID实际上并不重要1;其他人无法为该窗口注册热键,其他窗口的热键事件将发布到这些窗口。类似地,如果只为给定线程注册一个无窗口热键,则只会收到该热键的消息如果您控制应用程序的所有代码,您可以使用您想要分配的任何技术为热键选择任何ID;没有人会踩到它们,因为您拥有所有能够踩到它们的代码
但是,如果您正在编写一个可由其他代码调用的通用例程,该怎么办?您无法可靠地选择一个常量ID,因为调用者可能已经在使用该ID,如果他们也在使用相同的窗口或线程,您将重新定义他们的热键。或者,如果(如您的情况)您不知道在运行时之前将注册多少热键,该怎么办
您需要一种方法来确保您在运行时选择的ID不会被其他人使用。这就是GlobalAddAtom()
发挥作用的地方:您向它传递一个字符串,它将为您提供一个保证与该字符串相对应的ID,而不是其他ID;这对于系统来说实际上是唯一的,除非其他人传递相同的字符串-您可能会得到一个唯一的字符串;只需使用您的公司名称,或您的社会保险号码,以及为您需要的每个新原子增加的前缀。或者,如果你真的很偏执,使用GUID
真相背后的真相
有了这些,让我试着澄清一点困惑:Windows实际上并不关心调用RegisterHotKey()
的代码是否在DLL中。不可能。考虑下面的例程:
void RegisterSuperHappyFunHotKey(HWND hWnd, int id,
unsigned int fsModifiers, unsigned int vk)
{
RegisterHotKey(hWnd, id, fsModifiers, vk);
}
此例程只将其参数转发给WinAPI函数,而WinAPI函数都不能识别调用模块。如果它存在于DLL中,它的行为将与编译到应用程序本身的行为相同。Windows没有可靠的方法来判断调用的起始位置,热键本身被绑定到一个窗口和线程(或一个单独的线程),这两个线程都可以由DLL中的代码控制。当然,现在您可以有自己的应用程序或库特定要求:如果您的DLL创建了一个窗口并为其设置了热键,那么当您销毁窗口时,您需要注意注销该热键。。。但这是你自己的问题,你可以随心所欲地处理
MSDN指定两个ID范围有一个很好的理由:鼓励DLL作者避免踩到应用程序作者使用的ID。如果您是应用程序的作者,那么世界就是您的牡蛎-您可以控制(在大多数情况下)在应用程序的进程中加载和执行哪些代码,因此可以决定使用哪些ID,但您认为合适:从0开始,每个新热键递增是完全可以接受的。但是,一旦进入了ID的上限,就必须像使用DLL一样使用GlobalAddAtom()
,否则就有可能与从DLL加载的第三方代码以这种方式生成的ID发生冲突。这是一个。。。差不多
总结:
“共享DLL”位在这里是一个模糊的概念;如果您可以知道应用程序注册的所有热键的ID,那么只需在0xBFFF下面选择一个数字并使用它。如果你不能,因为你的代码
Assembly assembly = Assembly.GetCallingAssembly();
Boolean isDll = assembly.EntryPoint == null;