我创建了一个简单的Unicode窗口,我按下键盘上的一个键,看看WM_CHAR消息的wParam值是多少,它给了我预期的字符的Unicode代码点,我按下了“S”键和我的键盘布局设置为阿拉伯语(所以阿拉伯语字符是'س')。
现在,我还在Spy ++中捕获了窗口消息,但我注意到它给了我一个错误的wParam值,它实际上给了我Windows中的字符代码值:阿拉伯语代码页!
这是结果的屏幕截图:
这是源代码:
#define UNICODE
#include <Windows.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CHAR:
char str[256];
sprintf(str, "0x%.4x", wParam);
MessageBoxA(NULL, str, "", 0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(0, L"WinClass", L"My Title", WS_OVERLAPPEDWINDOW, 261, 172, 594, 384, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
答案 0 :(得分:8)
Spy ++如何工作是一个公开的秘密,您可以轻松地告诉您何时在.exe文件上运行Dumpbin.exe /imports
。对于spyxx_amd64.exe(64位版本),最相关的条目是:
SPYXXHK_AMD64.DLL
...
3 SpyxxCallWndRetProc
2 SpyxxCallWndProc
4 SpyxxGetMsgProc
USER32.dll
...
320 SetWindowsHookExW
31F SetWindowsHookExA
换句话说,它使用SetWindowsHookEx()来设置3个挂钩,WH_CALLWNDPROC,WH_CALLWNDPROCRET和WH_GETMESSAGE。 Spyxxhk_amd64.dll是注入每个进程的DLL,它包含钩子回调。
请注意,它使用两者 Unicode和Ansi版本的SetWindowsHookEx()。可以轻松解释结果的一种方法是在Unicode窗口上使用Ansi版本(SetWindowsHookExA)。这样的钩子只能观察WM_CHAR消息的Ansi版本。
请记住,当您在桌面上运行包含Unicode和Ansi窗口的进程时,Spy ++有一个不可能解决的问题,这种情况并不罕见,它无法让所有人都满意。最简单的假设是它只是将SetWindowsHookExA作为最小公分母。
实际上证明 Spy ++错误的做法要困难得多,而且我已经相当长一段时间了。任何试图在使用它时捕获Spy ++安装钩子的尝试都是一个破坏,钩子在程序启动时很早就安装好了。我最终发现的调试技术:
NtUserSetWindowHookEx
。在我的机器(Win8.1)上,它位于0x00007FFECC3BA970。有两个错误命中,MFC内部使用SetWindowsHookExW()。但随后它会亮起来,三次点击都看起来与此相似:
user32.dll!NtUserSetWindowsHookEx()
user32.dll!_SetWindowsHookEx() + 0x5b bytes
user32.dll!SetWindowsHookExAW() + 0x5b bytes
user32.dll!SetWindowsHookExA() + 0x11 bytes
spyxx_amd64.exe!SetMsgHook() + 0x6a bytes
spyxx_amd64.exe!HookMain() + 0x470 bytes
msvcr120.dll!_callthreadstart() Line 257 C
msvcr120.dll!_threadstart(void * ptd) Line 237 + 0x5 bytes C
kernel32.dll!BaseThreadInitThunk() + 0xd bytes
ntdll.dll!RtlUserThreadStart() + 0x34 bytes
哪个证明,你可以看到被调用的SetWindowsHookExA()。 Ansi版本,Spy ++只能显示WM_CHAR消息的Ansi版本。
答案 1 :(得分:0)
也许您在区域设置中将阿拉伯语代码页设置为默认值,并且Spy ++显示的值与您在没有Unicode支持的程序中相同?只是一个疯狂的猜测。