问题
I have a simple thread and inside the execute I try to call EnumWindows() with the address of one of the functions defined in the thread. So I'm trying to do this: EnumWindows(@cbEnumWindowsClickOK, 0); where cbEnumWindowsClickOK is an EnumWindowProc defined inside the thread class, like so:
TAutoClickOKThread = class(TThread)
private
fExitEvent : THandle;
function cbEnumWindowsClickOK(Wnd: HWND; Info: Pointer): BOOL;
public
constructor Create(ExitEvent : Thandle);
procedure Execute(); override;
end;
When I try this I keep getting "Error: Variable required", hinting that it doesn't interpret @cbEnumWindowsClickOK as an address. If I move the function to a global scope (removing it from the thread) it does work.
Any thoughts on how I can fix this?
回答1:
You have to pass EnumWindows a plain old function, i.e. one that is not bound to an instance. You must pass the instance in separately. Like this:
function EnumFunc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
begin
Result := TAutoClickOKThread(lParam).cbEnumWindowsClickOK(hwnd);
//note that there is now no need for the Info parameter
end;
...
procedure TAutoClickOKThread.Execute;
begin
...
EnumWindows(EnumFunc, LPARAM(Self));
...
end;
The reason it must be done this way is that an instance method does not match the required signature for EnumWindows. An instance method has an extra, implicit, parameter containing the instance reference, i.e. Self. This is how you are able to refer to instance members. But the signature for EnumFunc does not cater for this.
来源:https://stackoverflow.com/questions/7706637/how-to-pass-the-address-of-a-thread-function-as-a-callback-to-winapi