如何使用EnumWindows回调函数?

时间:2016-04-19 11:40:10

标签: windows api delphi winapi delphi-xe7

我希望有一个简洁的(关闭和自包含)函数(让我们称之为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

用它来传回结果是不对的?

2 个答案:

答案 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;