我希望有一个简洁的(关闭和自包含)函数(让我们称之为GetDesktopHandle),它返回桌面窗口的句柄。我使用下面的代码。但它只适用于DeskHandle是一个全局变种。
如何摆脱这个全局变量?如果我将它设为本地,当我尝试使用DeskHandle时,我会在getDesktopWnd中获得一个AV:= hChild
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;
主要问题是:我可以将此代码编写为单个函数或至少是否可以删除外部/全局变量?
可能的解决方案:
文档说第二个参数只是一个IN参数。
lParam [in] 类型:LPARAM 要传递给回调函数的应用程序定义值 https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
用它来传回结果是不对的?
答案 0 :(得分:3)
本地函数不能用作回调。如果您没有使用@
运算符来传递函数,编译器会告诉您。 (使用运算符将参数转换为普通的无类型指针,因此编译器不能再检查。)
你必须让你的回调成为一个独立的功能。
要在回调和来电者之间传递数据,请使用您当前命名为NotUsed
的第二个参数。例如,您可以将指针传递给句柄变量,然后回调可以取消引用指针以返回结果。
答案 1 :(得分:1)
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;