如何修改我的 EnumWindowNamesProc 以与 Lazarus 一起使用并使用 List 作为参数?

How can I modify my EnumWindowNamesProc to work with Lazarus and use a List as a parameter?

概览

我正在尝试枚举所有可见 window 名称的列表,然后填充作为参数传递的列表。

在 Delphi 中,我能够将其与以下内容一起使用:

function EnumWindowNamesProc(wHandle: HWND; List: TStrings): BOOL; stdcall;
var
  Title: array[0..255] of Char;
begin
  Result := False;

  GetWindowText(wHandle, Title, 255);
  if IsWindowVisible(wHandle) then
  begin
    if Title <> '' then
    begin
      List.Add(string(Title));
    end;
  end;
  Result := True;
end;

然后我可以这样调用上面的代码:

EnumWindows(@EnumWindowNamesProc, LPARAM(FWindowNames));

注意:FWindowNames 是在自定义 class 中创建的字符串列表。


问题

我也在尝试使函数与 Lazarus/FPC 兼容,但它不接受 List: TStrings 参数。

Lazarus 中的编译器错误抱怨类型不匹配(我已突出显示重要部分):

Error: Incompatible type for arg no. 1: Got " (address of function(LongWord;TStrings):LongBool;StdCall) ", expected " (procedure variable type of function(LongWord;LongInt):LongBool;StdCall) "

我可以通过像这样更改函数声明来阻止编译器抱怨:

{$IFDEF FPC}
  function EnumWindowNamesProc(wHandle: HWND; Param: LPARAM): BOOL; stdcall;
{$ELSE}
  function EnumWindowNamesProc(wHandle: HWND; List: TStrings): BOOL; stdcall;
{$ENDIF}
var
  Title: array[0..255] of Char;
begin
  Result := False;

  GetWindowText(wHandle, Title, 255);
  if IsWindowVisible(wHandle) then
  begin
    if Title <> '' then
    begin
      {$IFDEF FPC}
        // List no longer available
      {$ELSE}
        List.Add(string(Title));
      {$ENDIF}
    end;
  end;
  Result := True;
end;  

但后来我丢失了 List 参数。

我知道我可以修改代码并直接在函数内部使用 Listbox1,但我希望创建一个不需要了解 VCL/LCL 控件的可重用函数,相反我希望一个更优雅的解决方案,只需传递一个基于 TStrings 的参数并添加到此。


问题:

所以我的问题是,在 Delphi 中我可以将基于 TStrings 的参数传递给我的 EnumWindowNamesProc 但在 Lazarus 中它不会接受它。是否可能,如果可以,我该如何修改代码以便 Lazarus 接受 List: TStrings 参数?

可以。你不必失去你的 List.
只需使用正确的参数和类型转换

function EnumWindowNamesProc(wHandle: HWND; List: LPARAM): BOOL; stdcall;
var
  Title: array[0..255] of Char;
begin
  Result := False;

  GetWindowText(wHandle, Title, 255);
  if IsWindowVisible(wHandle) then
  begin
    if Title <> '' then
    begin
      TStringList(List).Add(string(Title));
    end;
  end;
  Result := True;
end;

EnumWindows(@EnumWindowNamesProc, LPARAM(list));

完成我的回答。还有一种选择——用指针自己定义函数(比如 Delphi)。然后就可以照样使用了

function EnumWindows(lpEnumFunc:Pointer; lParam:LPARAM):WINBOOL; external 'user32' name 'EnumWindows';