简体   繁体   English

Delphi XE2 EnumWindows无法正常工作

[英]Delphi XE2 EnumWindows not working properly

Using Delphi XE2 update 3 or update 4 on Win7 64 bit. 在Win7 64位上使用Delphi XE2更新3或更新4。

Calling enumwindows does not work like it used to work in Delphi 6. 调用enumwindows不像以前在Delphi 6中工作那样。

In Delphi 6 enumwindows processed windows until the callback function returned False. 在Delphi 6中,enumwindows处理了窗口,直到回调函数返回False。 That is what the documentation says it should do: 这就是文档说它应该做的事情:

"To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE." “要继续枚举,回调函数必须返回TRUE;要停止枚举,它必须返回FALSE。”

Making a call to enumwindows as follows: 按如下方式调用enumwindows:

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

Here is the callback function: 这是回调函数:

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;

Just to be clear the callback function is defined in code BEFORE the buttonclick event so it is found by the compiler without needing to be defined in the interface section. 为了清楚起见,回调函数在按钮单击事件之前的代码中定义,因此编译器可以找到它而无需在接口部分中定义。

If this is run using Delphi 6 the enumeration of windows stops once the False result is returned and GLBWindowHandle is not zero 如果使用Delphi 6运行,则一旦返回False结果且GLBWindowHandle不为零,则窗口的枚举将停止

If this is run using Delphi XE2 the enumeration continues after the False result is returned and GLBWindowHandle is always zero. 如果使用Delphi XE2运行,则在返回False结果并且GLBWindowHandle始终为零之后继续枚举。

WTF? WTF? Anybody have any ideas why the enumeration is not stopping like the documentation states it should and how it used to in Delphi 6? 任何人都有任何想法为什么枚举不会停止像文档说明它应该和它在Delphi 6中如何使用?

Cheers! 干杯!

This declaration is incorrect: 此声明不正确:

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

It should be: 它应该是:

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

You have to be careful not to mix up Boolean and BOOL since they are not the same thing. 你必须小心不要混淆BooleanBOOL因为它们不是同一个东西。 The former is a single byte, the latter is 4 bytes. 前者是单字节,后者是4字节。 This mismatch between what EnumWindows expects and what your callback function delivers is enough to cause the behaviour you observe. EnumWindows期望的与您的回调函数之间的不匹配足以导致您观察到的行为。


In addition, Rob Kennedy contributed this excellent comment: 此外,Rob Kennedy贡献了这一优秀评论:

The compiler can help find this error if you get out of the habit of using the @ operator before the function name when you call EnumWindows . 如果您在调用EnumWindowsEnumWindows在函数名之前使用@运算符,编译器可以帮助您找到此错误。 If the function signature is compatible, the compiler will let you use it without @ . 如果函数签名兼容,编译器将允许您在没有@情况下使用它。 Using @ turns it into a generic pointer, and that's compatible with everything, so the error is masked by unnecessary syntax. 使用@将其转换为通用指针,并且与所有内容兼容,因此错误会被不必要的语法所掩盖。 In short, using @ to create function pointers should be considered a code smell . 简而言之,使用@创建函数指针应该被视为代码气味


Discussion 讨论

Unfortunately the Windows.pas header translation defines EnumWindows in a most unhelpful manner, like this: 不幸的是, Windows.pas头转换以最无助的方式定义EnumWindows ,如下所示:

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

Now, the problem is in the definition of TFNWndEnumProc . 现在,问题在于TFNWndEnumProc的定义。 It is defined as: 它被定义为:

TFarProc = Pointer;
TFNWndEnumProc = TFarProc;

This means that you have to use the @ operator to make a generic pointer, because the function needs a generic pointer. 这意味着您必须使用@运算符来生成通用指针,因为该函数需要通用指针。 If TFNWndEnumProc were declared like this: 如果TFNWndEnumProc声明如下:

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

then the compiler would have been able to find the error. 然后编译器就能找到错误。

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);

The compiler rejects the call to EnumWindows with the following error: 编译器拒绝对EnumWindows的调用,并出现以下错误:

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

I think I will QC this issue and try my luck at persuading Embarcadero to stop using TFarProc . 我想我会TFarProc这个问题并试着说服Embarcadero停止使用TFarProc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM