如何将返回的WndProc / DlgProc句柄转换为函数地址?

时间:2018-01-31 09:46:07

标签: c winapi windows-kernel

在以下致电中,WndProc可以是returned as a handle

FARPROC pfn = (FARPROC)GetWindowLongPtr(hWnd, 
    DWLP_DLGPROC);  //same with GWLP_WNDPROC

有没有办法将它从用户模式代码转换为地址?

2 个答案:

答案 0 :(得分:2)

你需要下一个代码:

PVOID pfn = (IsWindowUnicode(hwnd) ? 
    GetWindowLongPtrW : GetWindowLongPtrA)(hwnd, GWLP_WNDPROC);

因此您需要根据GetWindowLongPtrW

的结果致电GetWindowLongPtrAIsWindowUnicode

注意:GetWindowLongPtrA(hwnd, GWLP_WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC) - 总是返回不同的结果 - 窗口过程的一个地址和另一个 - 表示窗口过程地址的句柄:特殊内部值仅对{{1}有意义} - 用于确定哪个版本 A W 检索窗口过程的地址 - 需要调用CallWindowProc。这是没有证件的,但是合理的。如果子类程序具有与原始程序相同的ANSI或UNICODE本机,它可以直接调用原始程序。如果本机不同 - 需要对窗口消息进行转换(Unicode< - > ANSI)(例如IsWindowUnicodeWM_GETTEXT ..)。

事实上WM_SETTEXT必须返回与GetWindowLongPtr(hwnd, GWLP_WNDPROC)

相同的值

但是SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWindowProc)设置了ansi窗口过程(在SetWindowLongPtrA中得到了指向CHAR字符串的指针)和WM_SETTEXT设置了unicode窗口过程(表示指向了SetWindowLongPtrW中的WCHAR字符串。因此,如果当前窗口过程和WM_SETTEXT的新设置具有相同的 A W - 新过程可以直接调用old,不进行转换,并且绝对合理{ {1}}返回旧Windows程序的直接地址。如果本机不同 - (我们为A设置A代表W或W代表) - 新窗口程序不能直接调用旧代码。在此之前,需要翻译一些Windows消息(SetWindowLongPtrSetWindowLongPtr等)。因为这和句柄在调用原始程序之前返回并且WM_GETTEXT翻译了消息。

示例显示WM_SETTEXT可以为同一窗口返回不同的值 - 基于当前窗口过程 - 是ansi还是Unicode:

CallWindowProc

并输出:

IsWindowUnicode

所以说文档:

  

窗口的字符集是通过使用来确定的    RegisterClass 功能。如果窗口类已注册   ANSI版本的 RegisterClass RegisterClassA ),字符集   窗口是ANSI。如果窗口类已注册   Unicode版本的 RegisterClass RegisterClassW ),字符集   窗口是Unicode。

不完全正确。它基于当前窗口过程Ansi或Unicode。最初这是基于if (HWND hwnd = CreateWindowExA(0, WC_STATICA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) { DbgPrint("IsWindowUnicode=%x\n", IsWindowUnicode(hwnd)); LONG_PTR l = GetWindowLongPtrW(hwnd, GWLP_WNDPROC); SetWindowLongPtrA(hwnd, GWLP_WNDPROC, l); DbgPrint("IsWindowUnicode=%x\n", IsWindowUnicode(hwnd)); SetWindowLongPtrW(hwnd, GWLP_WNDPROC, l); DbgPrint("IsWindowUnicode=%x\n", IsWindowUnicode(hwnd)); DestroyWindow(hwnd); } ,但可以通过IsWindowUnicode=1 IsWindowUnicode=0 IsWindowUnicode=1

进行更改

答案 1 :(得分:1)

你的问题没有意义。如果您在自己的代码中有窗口过程 - 更准确地说是在其中一个应用程序模块中 - GetWindowLongPtr(hWnd, DWLP_DLGPROC);将返回该地址。它只返回一个句柄,当没有明确的窗口过程时,它就是

  

...一个特殊的内部值,仅对CallWindowProc有意义。

这意味着消息由Windows内部代码直接处理,您甚至不应该猜测(*):它是Windows系统专用的。

(*)唯一的例外是如果您正在构建一个低级库,就像那些使用未记录的函数和结构的sysinternals那样。