Search code examples
delphilazarus

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


Overview

I am trying to enumerate a list of all visible window names and then populate a list passed as a parameter.

In Delphi I was able to get this to work with the following:

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;

Then I could call the above like so:

EnumWindows(@EnumWindowNamesProc, LPARAM(FWindowNames));

Note: FWindowNames is a stringlist created inside a custom class.


Problem

I am also trying to make the function compatible with Lazarus/FPC but it wont accept the List: TStrings parameter.

The compiler error in Lazarus complains about a type mismatch (I have highlighted the important parts):

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

I can stop the compiler complaining by changing the function declaration like so:

{$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;  

But then I lose my List parameter.

I know I could modify the code and use a Listbox1 for example directly inside the function but I was hoping to create a reusable function that does not need to know about VCL/LCL controls, instead I was hoping for a more elegant solution and simply pass a TStrings based parameter and add to this instead.


Question:

So my question is, in Delphi I am able to pass a TStrings based parameter to my EnumWindowNamesProc but in Lazarus it wont accept it. Is it possible, and if so, how can I modify the code so Lazarus accepts the List: TStrings parameter?


Solution

  • You can. You don't have to lose your List.
    Just use correct parameters and typecast

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

    To complete my answer. There is one more option - define the function by yourself with pointer (like in Delphi). Then you can use it the same way.

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