如何使用 EnumWindows 回调函数?
How to use the EnumWindows call back function?
我想要一个简洁的(封闭且独立的)函数(我们称它为 GetDesktopHandle),returns 桌面句柄 window。我使用下面的代码。但它只适用于 DeskHandle 是一个全局变量。
如何去掉这个全局变量?如果我把它放在本地,当我尝试 DeskHandle := hChild
时,我会在 getDesktopWnd 中得到一个 AV
VAR DeskHandle : HWND;
function GetDesktopHandle: HWND;
function getDesktopWnd (Handle: HWND; NotUsed: Longint): bool; stdcall; { Callback function }
VAR hChild : HWND;
begin
if handle <> 0 then
begin
hChild := FindWindowEx(handle, 0, 'SHELLDLL_DefView', nil);
if hChild <> 0 then
begin
hChild := FindWindowEx(hChild, 0, 'SysListView32', nil);
if hChild <> 0
then DeskHandle := hChild;
end;
end;
Result:= TRUE;
end;
begin
DeskHandle := 0;
EnumWindows(@getDesktopWnd, 0);
Result:= DeskHandle;
end;
主要问题 是:我可以将此代码编写为单个函数或至少,我可以去掉 external/global var 吗?
可能的解决方案:
文档说第二个参数只是一个IN参数。
lParam [in]
Type: LPARAM
An application-defined value to be passed to the callback function.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
用它传回结果会不会出错?
局部函数不能用作回调。如果您没有使用 @
运算符来传递您的函数,编译器会告诉您这一点。 (使用运算符将参数变成普通的无类型指针,因此编译器无法再检查。)
你必须让你的回调成为一个独立的函数。
要在回调和调用者之间传递数据,请使用您当前命名为 NotUsed
的第二个参数。例如,您可以将指针传递给句柄变量,然后回调可以取消引用指向 return 结果的指针。
type
TMyData = record
Handle: HWND;
Pid: DWORD;
Caption: String;
ClassName: String;
end;
PMyData = ^TMyData;
function GetWindowClass(const Handle: HWND): String;
begin
SetLength(Result, MAX_PATH);
SetLength(Result, GetClassName(Handle, PChar(Result), Length(Result)));
end;
function GetWindowCaption(const Handle: HWND): String;
begin
SetLength(Result, MAX_PATH);
SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result)));
end;
function EnumChildWindowsProc(Handle: THandle; MyData: PMyData): BOOL; stdcall;
var
ClassName: String;
Caption: String;
Pid: DWORD;
begin
ClassName := GetWindowClass(Handle);
Caption := GetWindowCaption(Handle);
Result := (ClassName = 'SysListView32') and (Caption = 'FolderView');
if Result then
begin
MyData.Handle := Handle;
GetWindowThreadProcessId(Handle, MyData.Pid);
MyData.Caption := Caption;
MyData.ClassName := ClassName;
end;
// To continue enumeration, the callback function must return TRUE;
// to stop enumeration, it must return FALSE
Result := not Result;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyData: TMyData;
begin
ZeroMemory(@MyData, SizeOf(MyData));
EnumChildWindows(GetDesktopWindow, @EnumChildWindowsProc, NativeInt(@MyData));
if MyData.Handle > 0 then
begin
ShowMessageFmt('Found Window in Pid %d', [MyData.Pid]);
end
else begin
ShowMessage('Window not found!');
end;
end;
我想要一个简洁的(封闭且独立的)函数(我们称它为 GetDesktopHandle),returns 桌面句柄 window。我使用下面的代码。但它只适用于 DeskHandle 是一个全局变量。
如何去掉这个全局变量?如果我把它放在本地,当我尝试 DeskHandle := hChild
时,我会在 getDesktopWnd 中得到一个 AVVAR DeskHandle : HWND;
function GetDesktopHandle: HWND;
function getDesktopWnd (Handle: HWND; NotUsed: Longint): bool; stdcall; { Callback function }
VAR hChild : HWND;
begin
if handle <> 0 then
begin
hChild := FindWindowEx(handle, 0, 'SHELLDLL_DefView', nil);
if hChild <> 0 then
begin
hChild := FindWindowEx(hChild, 0, 'SysListView32', nil);
if hChild <> 0
then DeskHandle := hChild;
end;
end;
Result:= TRUE;
end;
begin
DeskHandle := 0;
EnumWindows(@getDesktopWnd, 0);
Result:= DeskHandle;
end;
主要问题 是:我可以将此代码编写为单个函数或至少,我可以去掉 external/global var 吗?
可能的解决方案:
文档说第二个参数只是一个IN参数。
lParam [in] Type: LPARAM An application-defined value to be passed to the callback function.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
用它传回结果会不会出错?
局部函数不能用作回调。如果您没有使用 @
运算符来传递您的函数,编译器会告诉您这一点。 (使用运算符将参数变成普通的无类型指针,因此编译器无法再检查。)
你必须让你的回调成为一个独立的函数。
要在回调和调用者之间传递数据,请使用您当前命名为 NotUsed
的第二个参数。例如,您可以将指针传递给句柄变量,然后回调可以取消引用指向 return 结果的指针。
type
TMyData = record
Handle: HWND;
Pid: DWORD;
Caption: String;
ClassName: String;
end;
PMyData = ^TMyData;
function GetWindowClass(const Handle: HWND): String;
begin
SetLength(Result, MAX_PATH);
SetLength(Result, GetClassName(Handle, PChar(Result), Length(Result)));
end;
function GetWindowCaption(const Handle: HWND): String;
begin
SetLength(Result, MAX_PATH);
SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result)));
end;
function EnumChildWindowsProc(Handle: THandle; MyData: PMyData): BOOL; stdcall;
var
ClassName: String;
Caption: String;
Pid: DWORD;
begin
ClassName := GetWindowClass(Handle);
Caption := GetWindowCaption(Handle);
Result := (ClassName = 'SysListView32') and (Caption = 'FolderView');
if Result then
begin
MyData.Handle := Handle;
GetWindowThreadProcessId(Handle, MyData.Pid);
MyData.Caption := Caption;
MyData.ClassName := ClassName;
end;
// To continue enumeration, the callback function must return TRUE;
// to stop enumeration, it must return FALSE
Result := not Result;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyData: TMyData;
begin
ZeroMemory(@MyData, SizeOf(MyData));
EnumChildWindows(GetDesktopWindow, @EnumChildWindowsProc, NativeInt(@MyData));
if MyData.Handle > 0 then
begin
ShowMessageFmt('Found Window in Pid %d', [MyData.Pid]);
end
else begin
ShowMessage('Window not found!');
end;
end;