我需要創建一個用于處理訊息的視窗(WM_HOTKEY),所以我開始使用以下內容并使用 SetWindowLong 傳遞實體資訊以在 windowproc 中使用。
fWindow:=CreateWindowEx(WS_EX_TOOLWINDOW,MsgWndClass.lpszClassName,'',WS_POPUP,0,0,0,0,0,0,HInstance,nil);
SetWindowLong(fWindow,GWL_USERDATA,NativeInt(Self));
并且windowproc是
class function TMessageWindow.WindowProc(hWnd: HWND; uMsg: Integer; wParam: WPARAM; lParam: LPARAM): Integer;
begin
var I:=GetWindowLong(hWnd,GWL_USERDATA);
if I=0 then
Exit(DefWindowProc(hWnd,uMsg,wParam,lParam));
Result:=TMessageWindow(I).HandleMessage(uMsg,wParam,lParam);
end;
當我嘗試從 TMessageWindow 創建一個繼承的類時,我的問題出現了,而 HandleMessage 是虛擬的。
我發現雖然 HandleMessage 函式在繼承的類中被重寫,但 TMessageWindow(I) 的型別轉換正在呼叫基方法。
在四處尋找這個例子之后,我找不到任何使用 SetWindowLong 函式將資訊傳遞給 windowproc 的人的例子,所以現在我認為必須有更好的方法。
uj5u.com熱心網友回復:
首先,確保您的class方法也被標記為static洗掉隱藏Self引數,并且正在使用stdcall呼叫約定,如果您還沒有這樣做的話,例如:
class function WindowProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; static;
之后,如果您正在為 64 位編譯,則需要使用您的代碼(Get|Set)WindowLongPtr(),例如:
private
fWindow: HWND;
fWindow := ...;
SetWindowLongPtr(fWindow, GWLP_USERDATA, LONG_PTR(Self));
class function TMessageWindow.WindowProc(hWnd: HWND; uMsg: Integer; wParam: WPARAM; lParam: LPARAM): Integer; stdcall;
begin
var I := GetWindowLongPtr(hWnd, GWLP_USERDATA);
if I <> 0 then
Result := TMessageWindow(I).HandleMessage(uMsg, wParam, lParam)
else
Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
end;
或者,SetWindowSubclass()改為使用,例如:
private
fWindow: HWND;
class function SubclassWindowProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; static;
uses
..., Commctrl;
fWindow := ...;
SetWindowSubclass(fWindow, @TMessageWindow.SubclassWindowProc, 1, DWORD_PTR(Self));
class function TMessageWindow.SubclassWindowProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall;
begin
if uMsg = WM_NCDESTROY then
RemoveWindowSubclass(hWnd, @TMessageWindow.SubclassWindowProc, uIdSubclass);
Result := TMessageWindow(dwRefData).HandleMessage(uMsg, wParam, lParam);
// have HandleMessage() call DefSubclassProc() for any unhandled messages...
end;
That being said, an easier way to create a message window with a virtual message procedure is to use the RTL's AllocateHWnd() function instead, eg:
private
fWindow: HWND;
procedure HandleMessage(var Message: TMessage); virtual;
// to create the window:
fWindow := AllocateHWnd(HandleMessage);
// to destroy the window:
DeallocateHWnd(fWindow);
procedure TMessageWindow.HandleMessage(var Message: TMessage);
begin
with Message do
Result := DefWindowProc(fWindow, Msg, WParam, LParam);
end;
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/456757.html
上一篇:如何解決SpringRCE漏洞(CVE-2022-22965)?
下一篇:C#多執行緒下的調優
