Recent

Author Topic: Code compile in Delphi but not in Lazarus  (Read 10589 times)

antekgla

  • New Member
  • *
  • Posts: 22
Re: Code compile in Delphi but not in Lazarus
« Reply #15 on: June 22, 2017, 09:06:54 pm »
GetWindowText() expects you to specify the size of the buffer, *in chars, including the null terminator*.  You need to use +1 instead of +2, otherwise you are giving GetWindowText() permission to copy more chars than you have actually allocated room for.  The return value of GetWindowTextLength() does not include the null terminator.

I would do something more like the following instead:

Code: [Select]
unit Unit1;

{$MODE OBJFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls,
  Windows, StdCtrls;

type
  TForm1 = Class(TForm)
    Button1: TButton;
    Memo1  : TMemo;
    Procedure Button1Click (Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.LFM}

function GetWindowClassName(AHandle: HWND): string;
begin
  SetLength(Result, 255);
  SetLength(Result, GetClassName(AHandle, PChar(Result), Length(Result)+1));
end;

function GetWindowText(AHandle: HWND): UnicodeString;
var
  l: Integer;
begin
  Result := '';
  l := Windows.GetWindowTextLengthW(AHandle);
  if l > 0 then
  begin
    SetLength(Result, l);
    SetLength(Result, Windows.GetWindowTextW(AHandle, PWideChar(Result), l+1));
  end;
end;

type
  PMyEnumInfo = ^MyEnumInfo;
  MyEnumInfo = record
    Strings: TStrings;
    Level: Integer;
  end;

procedure AddWindowToList(AHandle: HWND: var AInfo: MyEnumInfo);
var
  tmpS: string;
  theWinText: UnicodeString;
begin
  tmpS := StringOfChar(' ', AInfo.Level) + GetWindowClassName(AHandle);
  theWinText := GetWindowText(AHandle);
  if theWinText <> '' Then
    tmpS := tmpS + ' <' + Utf8Encode(theWinText) + '>'
  else
    tmpS := tmpS + ' ""';
  AInfo.Strings.Add(tmpS);
end;

function EnumChildProc(AHandle: HWND; AParam: LPARAM): BOOL; stdcall;
begin
  Result := True;
  AddWindowToList(AHandle, PMyEnumInfo(AParam)^);
end;

function EnumWindowsProc(AHandle: HWND; AParam: LPARAM): BOOL; stdcall;
var
  Info: PMyEnumInfo;
  { alternatively:
  Info: PMyEnumInfo absolute AParam;
  }
begin
  Result := True;
  Info := PMyEnumInfo(AParam); // <-- omit this if using 'absolute' above
  AddWindowToList(AHandle, Info^);
  Inc(Info.Level);
  EnumChildWindows(AHandle, @EnumChildProc, AParam);
  Dec(Info.Level);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  info: MyEnumInfo;
begin
  info.Strings := TStringList.Create;
  try
    info.Level := 0;
    EnumWindows(@EnumWindowsProc, LPARAM(@info));
    Memo1.Lines.Assign(info.Strings);
  finally
    info.Strings.Free;
  end;

  { alternatively:
  Memo1.Lines.BeginUpdate;
  try
    Memo1.Clear;
    info.Strings := Memo1.Lines;
    info.Level := 0;
    EnumWindows(@EnumWindowsProc, LPARAM(@info));
  finally
    Memo1.Lines.EndUpdate;
  end;
  }
end;

end.

I try your code but sadly not compile.
Changing {$mode objfpc}{$H+} for {$Mode Delphi} make compiling possible but sadly dont produce any result in the Memo.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: Code compile in Delphi but not in Lazarus
« Reply #16 on: June 22, 2017, 09:27:08 pm »
I try your code but sadly not compile.

Why not?  What is the actual error?  On which line of code?  I don't have FreePascal installed, so I can't compile it myself, but I don't see anything in the code I posted that shouldn't compile in either mode.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: Code compile in Delphi but not in Lazarus
« Reply #17 on: June 22, 2017, 09:37:59 pm »
You have to set up a form with a memo and a button and connect the button for Remy's code to work?

Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

antekgla

  • New Member
  • *
  • Posts: 22
Re: Code compile in Delphi but not in Lazarus
« Reply #18 on: June 22, 2017, 09:49:34 pm »
I try your code but sadly not compile.

Why not?  What is the actual error?  On which line of code?  I don't have FreePascal installed, so I can't compile it myself, but I don't see anything in the code I posted that shouldn't compile in either mode.

Code: Pascal  [Select][+][-]
  1.  Inc(Info.Level);  

Code: Pascal  [Select][+][-]
  1.  Dec(Info.Level);  

both lines same error: Error: Illegal qualifier

Nevermind because with the {$Mode Delphi} compiles fine with 3 warnings: Hint: Conversion between ordinals and pointers is not portable

I checked again and after change the mode, the code produce the desired result in the memo.
My mistake (possible a bad copy/paste).

Thanks for this new code!

antekgla

  • New Member
  • *
  • Posts: 22
Re: Code compile in Delphi but not in Lazarus
« Reply #19 on: June 22, 2017, 09:51:36 pm »
You have to set up a form with a memo and a button and connect the button for Remy's code to work?

Yes!
Like I said in my last message. The code after change the mode {$Mode Delphi} works OK.
My mistake  :-[
...sorry
Thanks again Remy!

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: Code compile in Delphi but not in Lazarus
« Reply #20 on: June 23, 2017, 02:00:20 am »
Code: Pascal  [Select][+][-]
  1.  Inc(Info.Level);  

Code: Pascal  [Select][+][-]
  1.  Dec(Info.Level);  

both lines same error: Error: Illegal qualifier

Hmm, that means there is a naming conflict with something else in the code.  I have tweaked the variable names to help avoid that.

Nevermind because with the {$Mode Delphi} compiles fine with 3 warnings: Hint: Conversion between ordinals and pointers is not portable

It is not portable.  But as long as the ordinal is the same size as a pointer (which LPARAM should be), it is fine.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018