主题:将某些键替换为另一个键值。
例如,如果我按P,它应该是F24。
当我试图从.ini文件中加载键值时,钩子不再是全局的。它只有在对焦的情况下才能工作。
我的DLL代码:
extern "C" __declspec(dllexport) LRESULT CALLBACK KeyboardHook(int, WPARAM, LPARAM);
extern "C" __declspec(dllexport) void loadSettings(LPSTR);
bool shouldUpdateKey = false;
int ArcherKey;
LRESULT CALLBACK KeyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if ((lParam >> 20))
{
if (wParam == ArcherKey)
{
shouldUpdateKey = shouldUpdateKey ? false : true;
if (shouldUpdateKey)
{
MessageBox(NULL, L"ArcherKey", L"", MB_OK);
keybd_event(0x87, 45, 1, 0); //press F24
return 1;
}
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
LPSTR GetValueFromINI(LPSTR FileName, LPSTR Section, LPSTR Key)
{
char *key;
key = (char *)malloc(256);
GetPrivateProfileStringA(Section, Key, NULL, key, 256, FileName);
return key;
free(key);
}
void loadSettings(LPSTR FileName)
{
ArcherKey = atoi(GetValueFromINI(FileName, "HotKey", "Archer key"));
}我使用shouldUpdateKey来避免x2回调(当键按下和按下时)调用。另外,我尝试添加这个语句if (lParam >>31) ^ 1,但是这个语句总是假的。
.exe代码:
LRESULT(*pKeybHook)(int, WPARAM, LPARAM);
HHOOK hhookMsg;
void(*loadSettings)(LPSTR);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
/* default code */
HMODULE dll = LoadLibrary(_T("MainHookDLL.dll"));
if (dll)
{
pKeybHook = (LRESULT(*)(int, WPARAM, LPARAM)) GetProcAddress(dll, "_KeyboardHook@12");
loadSettings = (void(*)(LPSTR)) GetProcAddress(dll, "loadSettings");
loadSettings("C:\\Settings.ini");
hhookMsg = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)(pKeybHook), dll, 0);
}
/* defult code */
UnhookWindowsHookEx(hhookMsg); // unhook
FreeLibrary(dll);
return (int) msg.wParam;
} Settings.ini结构:
[HotKey]
Archer key=80所以我的问题是:如果尝试从文件中加载设置,钩子只能在活动的winapi窗口中工作。它显示MessageBox\等等,但仅以活动的winapi形式显示。如果将wParam == ArcherKey改为wParam == 80,则在所有应用程序中,它都能在全球范围内工作。我调试我的应用程序,在从.ini文件加载之后,我的ArcherKey = 80。所以我真的不明白我到底犯了什么错。
发布于 2014-10-21 18:54:29
据我回忆,如果钩子是全局的,包含HOOKPROC的DLL将在所有其他进程中加载。这意味着内存中有多个DLL实例。因为您调用了loadSettings(.)在您的应用程序中,只为该进程初始化ArcherKey的值。这会导致你所观察到的行为。
要改变这一点,您应该修改DllMain(..)函数的作用如下:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
loadSettings("C:\\Settings.ini");
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE;
}这将初始化钩子正在安装的所有进程的ArcherKey值,因为在加载DLL时,DllMain调用了DllMain。出于测试目的,您可以添加MessageBeep(0);在调用loadSettings(.)之前以验证代码部分是否已执行。
快速查看一下SetWindowsHookEx(.)的文档,我的担忧就成了现实:如果您正在编译一个32位的DLL,那么而不是将能够钩住64位进程,反之亦然。为了做到这一点,您必须用不同的名称为HOOKPROC实现dll的64位版本。
发布于 2014-10-21 18:38:32
钩子被“注入”到其他进程中,这意味着整个DLL将加载到所有相关进程中,就好像进程本身(例如Notepad.exe)调用了LoadLibrary()一样。因此,在这个上下文中(在另一个进程中,例如Notepad.exe),您的设置不会被加载,所以ArcherKey不会被初始化,所以消息框不会出现。
因此,您必须让您的DLL进行初始化,而不是单独的.exe。您可以通过ArcherKey on DLL_PROCESS_ATTACH上的DllMain初始化DLL_PROCESS_ATTACH(加载设置)(尽管在这一点上需要注意哪些API是安全的--大多数情况下,导致加载其他DLL的调用都是no-no),或者您可以添加大致为la的代码:
static DWORD initialized = 0;
static int ArcherKey;
LRESULT CALLBACK KeyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if (!initialized)
{
loadSettings();
}
...
}尽管这段代码根本不可取,因为长时间运行的钩子是最小的,相当糟糕的形式,并可能导致问题(例如,拖延该进程)。或者,您可以将数据放置在已知的共享位置。编辑:对于如何在对类似问题的公认答案中共享值,有一些很好的建议。
发布于 2014-10-22 07:48:39
LPSTR GetValueFromINI(LPSTR FileName, LPSTR Section, LPSTR Key)
{
char *key;
key = (char *)malloc(256);
GetPrivateProfileStringA(Section, Key, NULL, key, 256, FileName);
return key;
free(key); // <- will never happen
}
ArcherKey = atoi(GetValueFromINI(...)); // <- does not clean up内存泄漏
https://stackoverflow.com/questions/26493394
复制相似问题