Delphi XE2 EnumWindows无法正常工作

时间:2012-03-01 18:45:50

标签: delphi winapi delphi-xe2

在Win7 64位上使用Delphi XE2 update 3或update 4。

调用enumwindows不像以前在Delphi 6中工作那样。

在Delphi 6中,enumwindows处理了窗口,直到回调函数返回False。这就是文档说它应该做的事情:

“要继续枚举,回调函数必须返回TRUE;要停止枚举,它必须返回FALSE。”

按如下方式调用enumwindows:

procedure TForm1.Button1Click(Sender: TObject);
begin
  EnumWindows(@FindMyWindow,0);
  if GLBWindowHandle <> 0 then begin
    ShowMessage('found');
  end;
end;

这是回调函数:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): boolean; stdcall;
var TheText : array[0..150] of char;
str : string;
begin
Result := True;
GLBWindowHandle := 0;
if (GetWindowText(hWnd, TheText, 150) <> 0) then
   begin
   str := TheText;
   if str = 'Form1' then
      begin
      GLBWindowHandle := hWnd;
      Result := False;
      end
   else
      result := True;
   end;
end;

为了清楚起见,回调函数是在代码之前定义的,而不是在接口部分中定义,所以编译器会找到回调函数。

如果使用Delphi 6运行,则一旦返回False结果且GLBWindowHandle不为零,则窗口的枚举将停止

如果使用Delphi XE2运行,则在返回False结果并且GLBWindowHandle始终为零之后,枚举将继续。

WTF?任何人都有任何想法为什么枚举不会停止像文档说明它应该以及如何在Delphi 6中使用它?

干杯!

1 个答案:

答案 0 :(得分:12)

此声明不正确:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): boolean; stdcall;

应该是:

function FindMyWindow(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;

您必须小心,不要混淆BooleanBOOL,因为它们不是同一回事。前者是单字节,后者是4字节。 EnumWindows期望与回调函数提供的内容之间的这种不匹配足以导致您观察到的行为。


另外,Rob Kennedy提出了这个出色的评论:

  

如果您在调用@时不习惯在函数名前使用EnumWindows运算符,编译器可以帮助您找到此错误。如果函数签名兼容,编译器将允许您在不使用@的情况下使用它。使用@将其转换为通用指针,并且与所有内容兼容,因此错误会被不必要的语法掩盖。简而言之,使用@创建函数指针应该被视为代码气味


<强>讨论

不幸的是,Windows.pas标题翻译以最无助的方式定义EnumWindows,如下所示:

function EnumWindows(lpEnumFunc: TFNWndEnumProc; lParam: LPARAM): BOOL; stdcall;

现在,问题在于TFNWndEnumProc的定义。它被定义为:

TFarProc = Pointer;
TFNWndEnumProc = TFarProc;

这意味着使用@运算符来创建通用指针,因为该函数需要通用指针。如果TFNWndEnumProc被声明如下:

TFNWndEnumProc = function(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;

然后编译器就能找到错误。

type
  TFNWndEnumProc = function(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;

function EnumWindows(lpEnumFunc: TFNWndEnumProc;
  lParam: LPARAM): BOOL; stdcall; external 'user32';

function FindMyWindow(hWnd: HWND; lParam: LPARAM): Boolean; stdcall;
begin
  Result := False;
end;

....
EnumWindows(FindMyWindow, 0);

编译器拒绝对EnumWindows的调用,并出现以下错误:

  

[DCC错误] Unit1.pas(38):E2010不兼容的类型:'LongBool'和'Boolean'

我想我会质疑这个问题并试着说服Embarcadero停止使用TFarProc