Lazarus

Free Pascal => Beginners => Topic started by: Moombas on August 20, 2019, 11:47:15 am

Title: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 20, 2019, 11:47:15 am
Hi there,

I am new to Lazarus and I am coming from Emba Delphi Rio 10.3.2. I have to change because of decision of the company.
Now i tryed to Convert my Delphi Projekt into Lazarus, but there seem to be something todo for me manually.

1. I tryed to convert the unit, but i get two errors:
   A.: Problem when trying to repair the form file C:\....\*.lfm
   B:  Converting failed // i think because of the Problem above
2. I tryed to convert the project:
   A. Units missing: Vcl.Forms, Vcl. Themes, Vcl.Styles   //I are there Units from Lazarus to replace these (LCL.Forms or like that?)
   if I skip them i got additional:
   B. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System. Classes, Vcl.Graphics, Vcl.Controls, Vcl.Dialogs, Vcl.StdCtrls,
       Vcl.ComCtrls, Vcl.Grids, Vcl.ExtCtrls, System. UITypes, Data.DB, Vcl. DBGrids, System.StrUtils, FireDAC.Stan.Intf, FireDAC.Stan.Option,
       FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys,
       FireDAC.Phys.MySQL, FireDAC.MySQL.Def, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt,
       System.Win.Registry, FireDAC..Comp.Dataset, FireDAC.Client

Can someone tell me what to do or where i can find information to fix this to use in Lazarus?

Ok, i think most of them i could fix, but the firedac are missing and the "Problem when trying to repair the form file C:\....\*.lfm" is the most significant one which i can't fix.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: k1ng on August 20, 2019, 02:21:32 pm
   B. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System. Classes, Vcl.Graphics, Vcl.Controls, Vcl.Dialogs, Vcl.StdCtrls,
       Vcl.ComCtrls, Vcl.Grids, Vcl.ExtCtrls, System. UITypes, Data.DB, Vcl. DBGrids, System.StrUtils, FireDAC.Stan.Intf, FireDAC.Stan.Option,
       FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys,
       FireDAC.Phys.MySQL, FireDAC.MySQL.Def, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt,
       System.Win.Registry, FireDAC..Comp.Dataset, FireDAC.Client

Title: Re: Convert Errors Delphi -> Lazarus
Post by: valdir.marcos on August 20, 2019, 03:33:43 pm
I am new to Lazarus and I am coming from Emba Delphi Rio 10.3.2. I have to change because of decision of the company.
Now i tryed to Convert my Delphi Projekt into Lazarus, but there seem to be something todo for me manually.
...
Can someone tell me what to do or where i can find information to fix this to use in Lazarus?
I think you should step back and learn a little more about Lazarus before converting your Delphi project.
Maybe this information helps you:
https://wiki.freepascal.org/Databases
https://wiki.freepascal.org/SQLdb_Programming_Reference
https://wiki.freepascal.org/SQLdb_Package
https://wiki.lazarus.freepascal.org/SqlDBHowto
https://wiki.freepascal.org/Lazarus_Database_Overview
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 20, 2019, 04:00:59 pm
I solved it now.
I Removed FireDAC completely and put in the LAzarus Components instead and so the lfm works as fine as suspected.
And the other issues i got solved too ("System." etc. removed).
T hink i have a bit to learn where Lazarus works different from IDE.  ;)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on August 20, 2019, 04:03:48 pm
I think you should step back and learn a little more about Lazarus before converting your Delphi project.
Absolutely! Begin with small projects and try to learn Lazarus and in particular what is different from Delphi. When you feel comfortable convert small Delphi projects to Lazarus using only VCL classes (no fancy database and third-party stuff). The basic conversion principles are for me:
Title: Re: Convert Errors Delphi -> Lazarus
Post by: valdir.marcos on August 20, 2019, 05:33:17 pm
Can someone tell me what to do or where i can find information to fix this to use in Lazarus?
Try to search the Lazaruz Forum as much as you can. There are many great discussions as the one below about converting or migrating Delphi projects to Lazarus:
extracting part of a Delphi5 dfm (https://forum.lazarus.freepascal.org/index.php/topic,42551.0.html)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: avra on August 20, 2019, 08:43:09 pm
https://wiki.freepascal.org/Lazarus_For_Delphi_Users
https://wiki.freepascal.org/Code_Conversion_Guide
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 22, 2019, 08:39:30 am
All differences have been found and the project now works as in Delphi.
A second project has been transfered succesfully too.

Is there a way that lazarus removes the namespaces (e.g.  "System.") by itself when it transfers the project?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on August 22, 2019, 09:23:55 am
All differences have been found and the project now works as in Delphi.
A second project has been transfered succesfully too.

Is there a way that lazarus removes the namespaces (e.g.  "System.") by itself when it transfers the project?

Actually you do not have to remove them at all. You can use the -FN compiler option to add the namespaces.
https://wiki.freepascal.org/FPC_New_Features_3.0#Delphi-like_namespaces_units.

(This feature somehow went under the radar of lazarus developers)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 22, 2019, 11:29:45 am
Hmm i wil take a look at this.

I am a bit confused of a malfunction from "movefile"

Lazarus has problems with umlauts (is this the right translation?).  So if i try to copy a file with umlauts, it doesn't work.

How to fix this?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 01:19:34 pm
  • Rename the form's dfm file to lfm (but keep the original). Rewrite the {$R *.dfm} to {$R *.lfm}
  • Rename the dpr project file to lpr (but keep the original). Add  "InterfaceBase" as first unit to the uses clause.

dfm and .dpr can be kept. It is not necessary to change this. Only the conversion wizard is still biassed to do this conversion (and similarly to force objfpc on unsuspecting users), but this is no longer necessary, which is why I avoid it as the plague.

I include a .inc file after the 'interface" line in every unit.  I handle mode setting there. (for both fpc and delphi, e.g. in Delphi it turns pointermath on, for FPC compat )

Quote
  • When there is messsage handling rename all WM_* to LM_*, TMessage to TLMessage, TWMLButtonDown to TLMLButtonDown and so on.

But only for GUI related messages (the ones that Lazarus emulates). WM_USER and system messages should be kept WM_

Quote
  • All (?) of this work can be handled by the Delphi-to-Lazarus converter. But I never understood what it is doing. And it is more fun to understand what is happening.

IMHO causes more troubles than it solves. Just open the Dpr, and the forms one by one. If you do it repeatedly (e.g. you keep the main codebase in delphi), look for "dfmcleaner (By Alan Bauer?). Oriignally meant for dfm conversion between delphi versions, you can routinely clean your dfm of certain properties (like dropdownrows below).

I worked on conversion of a simple zeos db app a few weeks back, note I skipped some things that are already fixed, but might not be in release versions.

Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 01:21:17 pm
Actually you do not have to remove them at all. You can use the -FN compiler option to add the namespaces.
https://wiki.freepascal.org/FPC_New_Features_3.0#Delphi-like_namespaces_units.

Afaik 3.0 has dotted units, but only 3.2 has -FN
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on August 22, 2019, 02:07:46 pm
But when he keeps Delphi's dotted unit names in the unit then shouldn't the unit files be named in the same way? I doubt that Lazarus is searching for a file "vcl.forms.pas" when "vcl.forms" is in the uses clause.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 02:14:55 pm
But when he keeps Delphi's dotted unit names in the unit then shouldn't the unit files be named in the same way? I doubt that Lazarus is searching for a file "vcl.forms.pas" when "vcl.forms" is in the uses clause.

Yes indeed. -FN works for the opposite case ("forms" in source and vcl.forms on disc).  Manually trimming prefixes , and configuring the prefixes in Delphi to keep it working is the easiest way long term in my experience.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 22, 2019, 02:52:32 pm
I Think this is for now not my problem but thanks for the help.

Actually i have these problems on my converted project:

1. A malfunction from "movefile": Lazarus has problems with umlauts.  So if i try to move a file with umlauts, it doesn't work. Is there any way to fix it (or have i work without umlauts)?

Code: Pascal  [Select]
  1.   movefile(PChar(Path + CSVList.Items.Strings[i]), PChar(Path + 'Archiv\' + CSVList.Items.Strings[i]));
  2.  


2. - fixed - logic failure
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 03:38:49 pm
Unicode is something that a whole book can be written around. Sufficient to say that Lazarus is a mix of old and new delphi and then some.

However your first problem is easy to fix:

I Think this is for now not my problem but thanks for the help.

Actually i have these problems on my converted project:

1. A malfunction from "movefile": Lazarus has problems with umlauts.  So if i try to move a file with umlauts, it doesn't work. Is there any way to fix it (or have i work without umlauts)?

Movefile is movefileA on Lazarus and movefilew on Delphi 2009 and later.
string is ansistring containing utf8 on lazarus (8-bit unicode mostly) and  unicodestring (16-bit unicode) on Delphi 2009 and later. Conversion between both is pretty seamless.

Solution: use movefilew and a wrapper procedure:

Code: Pascal  [Select]
  1. procedure mymovefile(src,target:unicodestring);
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on August 22, 2019, 06:30:56 pm
Code: Pascal  [Select]
  1. procedure mymovefile(src,target:unicodestring);
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;

Code: Pascal  [Select]
  1. procedure movefile(src,target:unicodestring);overload;
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;
Wouldn't that work yet?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 07:48:01 pm
Code: Pascal  [Select]
  1. procedure mymovefile(src,target:unicodestring);
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;

Code: Pascal  [Select]
  1. procedure movefile(src,target:unicodestring);overload;
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;
Wouldn't that work yet?

No.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on August 22, 2019, 08:50:18 pm
Sigh.  :D
Title: Re: Convert Errors Delphi -> Lazarus
Post by: winni on August 22, 2019, 09:57:54 pm
RenameFiles also moves files - vice versa it's old Unix tradition.

And RenameFileUTF8 hopefully converts your umlauts, Umlaute (or whatever)  correct.

From LazFileUtils.xml:

RenameFileUTF8

          Renames a file to the specified value
          RenameFileUTF8 is a Boolean function used to rename a file to the specified new value.
          For the Windows enviroment, MoveFileW is called to rename the file using the values         
          specified in OldName and NewName. For UNIX-like enviroments, DeleteFile in SysUtils is     
          called to delete the specified file name. InvalidateFileStateCache is also called.
         
           The return value is True if the file is renamed successfully.


Winni
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 10:39:00 pm
Sigh.  :D

I was thinking that it won't work because you must match unicodestring,unicodestring prototype to trigger the overload. Any combination of strings is down converted to the primary 1-byte string type.

However the windows version is p(ansi)char, not ansistring. So my guess you will just get a "don't know which overload to call".
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 22, 2019, 10:42:41 pm
RenameFiles also moves files - vice versa it's old Unix tradition.

And RenameFileUTF8 hopefully converts your umlauts, Umlaute (or whatever)  correct.

With FPC 3.0, RTL renamefile should work fine and fileutils -UTF8 versions are legacy. However this thread is about windows unit, which is a pure windows api header which does not play nice with Lazarus' string conventions. You need to call the -W versions in that case.

But afaik Windows rename (and move too) does not move files across volumes, unless options are given.

IIRC I used MoveFileExW(pwidechar(src),pwidechar(s2),MOVEFILE_COPY_ALLOWED)  to force it to move across volumes.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: winni on August 22, 2019, 11:12:20 pm
Hi!

I was not quiet shure, but I remembered to move file between different disks with renamefile in windows.

And indeed: If you look in winlazfileutils.inc then you see that RenameFileUTF8 does nothing but to call MoveFileW!

Line  230 ff:

Code: Pascal  [Select]
  1. function RenameFileUtf8(const OldName, NewName: String): Boolean;
  2. begin
  3.   Result:=MoveFileW(PWideChar(UTF8Decode(OldName)), PWideChar(UTF8Decode(NewName)));
  4. end;                                                                    
  5.  

Winni
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 23, 2019, 08:29:38 am
Solution: use movefilew and a wrapper procedure:

Code: Pascal  [Select]
  1. procedure mymovefile(src,target:unicodestring);
  2. begin
  3.  movefilew (pwidechar(src),pwidechar(dest),.... other params);
  4. end;

Thanks a lot, this works fine.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: PascalDragon on August 23, 2019, 09:24:27 am
All differences have been found and the project now works as in Delphi.
A second project has been transfered succesfully too.

Is there a way that lazarus removes the namespaces (e.g.  "System.") by itself when it transfers the project?

Actually you do not have to remove them at all. You can use the -FN compiler option to add the namespaces.
https://wiki.freepascal.org/FPC_New_Features_3.0#Delphi-like_namespaces_units.

(This feature somehow went under the radar of lazarus developers)
As marcov already wrote the -FN option was only added in 3.1.1 and is thus only available there (I should really add an entry for the 3.2 features page...).

Also the switch wouldn't be able to solve anything, because the units would need to exist with the namespaces which they don't.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 23, 2019, 10:47:56 am
So, i got the next problem:

Identifier not found: ReadDirectoryChangesW

Is there a Lazarus specific Unit i have to add or an other function to use?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: nouzi on August 23, 2019, 11:10:26 am
So, i got the next problem:

Identifier not found: ReadDirectoryChangesW

Is there a Lazarus specific Unit i have to add or an other function to use?
See this
https://forum.lazarus.freepascal.org/index.php?topic=44903.0
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 23, 2019, 11:27:27 am
(note that development  FPC versions do have it now)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 23, 2019, 11:50:01 am
ok, got it now, added it to project instead of the externeal unit -.-

But i Get an error to RDCWProcessMonitor (included in DirMonitor):

Code: Pascal  [Select]
  1. procedure TProcessMonitor.Execute;
  2. var
  3.   state:cardinal;
  4.   quit:boolean;
  5.   parent:TDirMonitor;
  6.   numBytes: DWORD;
  7. begin
  8.   { Place thread code here }
  9.   quit:=false;
  10.   parent:=TDirMonitor(self.FProRef);
  11.   while (not quit) do
  12.   begin
  13.     GetQueuedCompletionStatus( parent.FCompletionPort, numBytes, state, parent.FPOverlapped, INFINITE);  //Got LongWord expected QWord
  14. //...
  15.  

Edited it now to QWord and its working.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 23, 2019, 02:52:24 pm
Ok, next there are two problems:

1. The application Crashes when following Code is processed:
Code: Pascal  [Select]
  1. procedure TTools.ToolbarSet(ToolE : TLabeledEdit; ToolI : TImage; ToolC : TCheckbox; ToolN : TLabeledEdit; ToolB : TButton);
  2. var
  3.   i, bs, lc : integer;
  4.   icon   : TIcon;
  5.   Filter : LPWord;
  6. begin
  7.   bs     := 0;
  8.   lc     := 0;
  9.  
  10.   if ToolE.Text <> '' then
  11.   begin
  12.     Icon := TIcon.Create;
  13.     try
  14.       ToolC.Checked := True;
  15.       for i := 1 to length(ToolE.Text) do
  16.       begin
  17.         if ToolE.Text[i] = '\' then
  18.         begin
  19.           inc(bs);
  20.         end;
  21.         if ToolE.Text[i] = ' ' then
  22.         begin
  23.           inc(lc);
  24.         end;
  25.       end;
  26.       if ToolN.Text <> '' then
  27.       begin
  28.         ToolB.Caption := ToolN.Text
  29.       end else
  30.       begin
  31.            ToolB.Caption := split(ToolE.Text, '\', bs - 1 + lc);
  32.       end;
  33.  
  34.       Icon.Handle := ExtractAssociatedIcon (hInstance, PChar(ToolE.Text), Filter);  //Crashes here. But Why? In Delphi its working nice.
  35.  
  36.       ToolI.Picture.Icon := icon;
  37.       if GetFileVersion(ToolE.Text) <> 'No version specification' then
  38.         ToolI.Hint := GetFileVersion(ToolE.Text);
  39.     finally
  40.       ToolI.show;
  41.       icon.Free;
  42.     end;
  43.     ToolB.Show;
  44.   end else
  45.   begin
  46.     ToolI.hide;
  47.     ToolB.Hide;
  48.     ToolC.Checked := False;
  49.   end;
  50. end;  
  51.  

2.  The SHA256 coding doesn't work. Below code works fine in Delphi:
Code: Pascal  [Select]
  1. var
  2.   newPW : String;
  3. begin
  4.   newPW := ThashSHA2.GetHashString(newPW), SHA256);
  5. end;
  6.  

3. Ini doen't read as Unicode (again the Problem with the umlauts):
Code: Pascal  [Select]
  1. Delay.Text          := Ini.ReadString ('Install' , 'Delay'               , '15');  
  2.  
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on August 23, 2019, 03:39:02 pm
2.  The SHA256 coding doesn't work. Below code works fine in Delphi:
Code: Pascal  [Select]
  1. var
  2.   newPW : String;
  3. begin
  4.   newPW := ThashSHA2.GetHashString(newPW), SHA256);
  5. end;
  6.  
Of course that does not work, not even in Delphi, it should throw a syntax error.' )' expected ';' found
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 23, 2019, 03:51:21 pm
Yeah okay, it was a cut out. Originally it has been a
Code: Pascal  [Select]
  1.   showmessage(ThashSHA2.GetHashString(newPW), SHA256);
  2.  
to control the output only during testing. (Copy/Paste error only here in forum)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Xor-el on August 23, 2019, 04:07:12 pm
Yeah okay, it was a cut out. Originally it has been a
Code: Pascal  [Select]
  1.   showmessage(ThashSHA2.GetHashString(newPW), SHA256);
  2.  
to control the output only during testing. (Copy/Paste error only here in forum)

ShowMessage does not have an overload accepting 2 parameters so your code is still wrong.

I guess this is what you meant.

Code: Pascal  [Select]
  1. showmessage(THashSHA2.GetHashString(newPW, TSHA2Version.SHA256));
  2.  

Well, in simple terms, there is no direct alternative to that function THashSHA2 inbuilt in FPC but there are external alternatives available that can be installed from OPM which includes HashLib4Pascal and DCPCrypt.

Using HashLib4Pascal, this code below should work for you.

Code: Pascal  [Select]
  1. ShowMessage(THashFactory.TCrypto.CreateSHA2_256().ComputeString(newPW, TEncoding.UTF8).ToString());
  2.  

Update
Forgot to indicate originally that you need to add HlpHashFactory to the uses clause of your unit.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: PascalDragon on August 23, 2019, 04:12:20 pm
As marcov already wrote the -FN option was only added in 3.1.1 and is thus only available there (I should really add an entry for the 3.2 features page...).
I've now added it to FPC New Features 3.2 (https://wiki.freepascal.org/FPC_New_Features_3.2#Default_unit_scopes) as it should be. :D
Title: Re: Convert Errors Delphi -> Lazarus
Post by: JuhaManninen on August 23, 2019, 05:31:05 pm
3. Ini doen't read as Unicode (again the Problem with the umlauts):
Code: Pascal  [Select]
  1. Delay.Text          := Ini.ReadString ('Install' , 'Delay'               , '15');
It is read correctly if the file contains Unicode text with UTF-8 encoding.
You should read this page to understand Unicode in Lazarus:
 https://wiki.lazarus.freepascal.org/Unicode_Support_in_Lazarus
You only seldom need to call Windows API. Most often you can use the cross-platform functions provided by FPC and Lazarus libraries.
Although this forum section is for FPC, you are working with a Lazarus application now, right?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 26, 2019, 08:33:20 am
@Juha: I've found the problem to the ini-file (File was unicode), saved as utf8 and now the correct path is read.


Yes, thought this is right place but change section if I am wrong here.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 26, 2019, 09:20:30 am
Hash now works fine, found which i have to add to uses additional. Thanks to Xor-el
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 26, 2019, 11:31:47 am
I do not get out of the umlaut problem -.-

I call a function:
Code: Pascal  [Select]
  1. OpenExcel(ExcelE.Text, FXLApp);     //ExcelE.Text = Path to the file. Path includes umlauts
  2.  

The function:
Code: Pascal  [Select]
  1. function OpenExcel(AFileName : string; var AXLApp : OleVariant):boolean;
  2. begin
  3.   Result := false;
  4.   // Wenn noch offen, dann schlie├čen..
  5.   CloseExcel(AXLApp);
  6.  
  7.   // Create Excel-OLE Object
  8.   try
  9.     AXLApp := CreateOleObject('Excel.Application');
  10.     Result := True;
  11.   except
  12.     On E:Exception do
  13.     begin
  14.       // Log Exception, wenn kein Excel installiert!
  15.       ShowMessage('Error INIT : ' + E.Message);
  16.     end;
  17.   end;
  18.  
  19.   if Result then begin
  20.     try
  21.       AXLApp.Visible := False;
  22.       AXLApp.Workbooks.OpenXML(AFileName);  //Get Error here (can't find '')
  23.     except
  24.       On E:Exception do
  25.       begin
  26.         // Log Exception, wenn Datei nicht vorhanden!
  27.         ShowMessage('Error OPEN : ' + E.Message);
  28.         // Excel wieder schlie├čen, da nicht gebraucht
  29.         CloseExcel(AXLApp);
  30.       end;
  31.     end;
  32.   end;
  33. end;  
  34.  

If i change the path to some without umlaut, it works fine but i can't change the path (networkpath);
And if i use Unicodestring() i get an exception (SIGSEGV).
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 26, 2019, 12:02:43 pm
Try making the parameter of the procedure "widestring"
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on August 26, 2019, 12:02:53 pm
This is how it works for me:
Code: Pascal  [Select]
  1. var
  2.   ws: WideString;
  3. ...
  4.   ws := UTF8Decode(AFileName);
  5.   AXLApp.Workbooks.OpenXML(ws);

AFileName comes from your Lazarus program and, therefore, is a UTF8-encoded AnsiString. Excel requires a WideString. It certainly can be done otherwise, but as an old-fashioned guy I prefer the direct conversion with UTF8Decode() (direct assignment "ws := AFileName" works, too, at least in fpc 3.0+). Interestingly, putting this into the OpenXML call directly (without the intermediate variable) does not work - strange...
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on August 26, 2019, 12:30:14 pm
Why didn't i try widestring, all other things i have tried  :-[ yes tis works fine now.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: marcov on August 26, 2019, 12:56:31 pm
Interestingly, putting this into the OpenXML call directly (without the intermediate variable) does not work - strange...

Probably the argument is a variant. So it is the Lazarus utf8 style 1-byte string to variant conversion that is the problem. But if you type the whole COM related procedure in widestrings and pass your lazarus strings to it, it gets autoconverted and works quite fine

See it as a kind of boxing problem. If you put a type X into a variant that supports X, you get a variant with X inside.

For the Lazarus side, X is ansistring, while for the COM kind it must be widestring.

Why unicodestring goes wrong I don't know. Maybe it prefers ansistring over widestring in the "to-variant" conversion.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 05, 2019, 10:33:23 am
Next Step  :o

I get an Error by using:
Code: Pascal  [Select]
  1.   private
  2.     { Private-Deklarationen }
  3.     Watch: TDirectoryWatch;  
  4.  
  5. procedure TTools.NewLog(Path : widestring);
  6. begin
  7.   if sFileAction = 'Create' then
  8.   begin
  9.     if SysUtils.ForceDirectories(Path) then
  10.       begin
  11.         LogL.Caption       := 'Auf Log Datei warten...';
  12.         LogL.Show;
  13.         Programs.Enabled   := False;
  14.         Data.Enabled       := False;
  15.         TxTLogs.Enabled    := False;
  16.         Watch              := TDirectoryWatch.Create; //Fails here!
  17.         Watch.WatchOptions := [woFileName, woDirName, woAttributes, woSize, woLastWrite, woLastAccess, woCreation, woSecurity];
  18.         Watch.WatchActions := [waAdded];
  19.         Watch.Directory    := Path;
  20.         Watch.OnNotify     := OnNotify;
  21.         Watch.Start;
  22.       end else
  23.       begin
  24.         MessageDlg('Verzeichnis konnte nicht erstellt werden', TMsgDlgType.mtError, [mbOK], 0)
  25.       end;
  26.   end else
  27.   begin
  28.     if sFileAction = 'Edited' then
  29.     begin
  30.       FileChange     := ReportFileTimes(Path);
  31.       olddate        := FileChange;
  32.       Timer3.Enabled := True;
  33.     end;
  34.   end;
  35. end;  
  36.  

TDirectoryWatch here:
Code: Pascal  [Select]
  1. (*
  2.  * This software is distributed under BSD license.
  3.  *
  4.  * Copyright (c) 2009 Iztok Kacin, Cromis (iztok.kacin@gmail.com).
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without modification,
  8.  * are permitted provided that the following conditions are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright notice, this
  11.  *   list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright notice, this
  13.  *   list of conditions and the following disclaimer in the documentation and/or
  14.  *   other materials provided with the distribution.
  15.  * - Neither the name of the Iztok Kacin nor the names of its contributors may be
  16.  *   used to endorse or promote products derived from this software without specific
  17.  *   prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  23.  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  27.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  28.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * NOTICE OF CODE ORIGIN
  31.  *
  32.  * This code was derived from the original code of author "Gleb Yourchenko"
  33.  * The original code "FnugryDirWatch" can still be found at Torry Components
  34.  * The URL is: http://www.torry.net/pages.php?id=252
  35.  *
  36.  * The code was taken as a starting point and then mainly written from scratch
  37.  * keeping some of the healthy code parts. So I am not in any way an author of
  38.  * the original idea. But I am the author of all the changes and new code parts.
  39.  *
  40.  * ============================================================================
  41.  * 12/10/2009 (1.0.0)
  42.  *  - Initial code rewrite from "FnugryDirWatch"
  43.  * 16/01/2010 (1.0.1)
  44.  *  - Refactored the main watch loop
  45.  * ============================================================================
  46. *)
  47.  
  48. unit DirectoryWatch;
  49.  
  50. {$MODE Delphi}
  51. {$WARN 5057 off : Local variable "$1" does not seem to be initialized}
  52. interface
  53.  
  54. uses
  55.    Windows, LCLIntf, LCLType, LMessages, SysUtils, FileUtil, Classes, Messages,
  56.    SyncObjs, RDCWProcessMonitor, RDCWDirMonitor;
  57.  
  58. const
  59.   FILE_NOTIFY_CHANGE_FILE_NAME   = $00000001;
  60.   FILE_NOTIFY_CHANGE_DIR_NAME    = $00000002;
  61.   FILE_NOTIFY_CHANGE_ATTRIBUTES  = $00000004;
  62.   FILE_NOTIFY_CHANGE_SIZE        = $00000008;
  63.   FILE_NOTIFY_CHANGE_LAST_WRITE  = $00000010;
  64.   FILE_NOTIFY_CHANGE_LAST_ACCESS = $00000020;
  65.   FILE_NOTIFY_CHANGE_CREATION    = $00000040;
  66.   FILE_NOTIFY_CHANGE_SECURITY    = $00000100;
  67.  
  68. const
  69.   cShutdownTimeout = 3000;
  70.  
  71. type
  72.   // the filters that control when the watch is triggered
  73.   TWatchOption = (woFileName, woDirName, woAttributes, woSize, woLastWrite,
  74.                   woLastAccess, woCreation, woSecurity);
  75.   TWatchOptions = set of TWatchOption;
  76.  
  77.   // the actions that are the result of the watch being triggered
  78.   TWatchAction = (waAdded, waRemoved, waModified, waRenamedOld, waRenamedNew);
  79.   TWatchActions = set of TWatchAction;
  80.  
  81.   TFileChangeNotifyEvent = procedure(const Sender: TObject;
  82.                                      const Action: TWatchAction;
  83.                                      const FileName: widestring
  84.                                      ) of object;
  85.  
  86.   TDirectoryWatch = class
  87.   private
  88.     FWatchOptions : TWatchOptions;
  89.     FWatchActions : TWatchActions;
  90.     FWatchSubTree : Boolean;
  91.     FWatchThread  : TThread;
  92.     FWndHandle    : HWND;
  93.     FDirectory    : widestring;
  94.     FAbortEvent   : Cardinal;
  95.     FOnChange     : TNotifyEvent;
  96.     FOnNotify     : TFileChangeNotifyEvent;
  97.     procedure WatchWndProc(var Msg: TMessage);
  98.     procedure SetDirectory(const Value: widestring);
  99.     procedure SetWatchOptions(const Value: TWatchOptions);
  100.     procedure SetWatchActions(const Value: TWatchActions);
  101.     procedure SetWatchSubTree(const Value: Boolean);
  102.     procedure DeallocateHWnd(Wnd: HWND);
  103.     function MakeFilter: Integer;
  104.   protected
  105.     procedure Change; virtual;
  106.     procedure AllocWatchThread;
  107.     procedure ReleaseWatchThread;
  108.     procedure RestartWatchThread;
  109.     procedure Notify(const Action: Integer;
  110.                      const FileName: widestring
  111.                      ); virtual;
  112.   public
  113.     constructor Create;
  114.     destructor Destroy; override;
  115.     procedure Start;
  116.     procedure Stop;
  117.     function Running: Boolean;
  118.     property WatchSubTree: Boolean read FWatchSubTree write SetWatchSubTree;
  119.     property WatchOptions: TWatchOptions read FWatchOptions write SetWatchOptions;
  120.     property WatchActions: TWatchActions read FWatchActions write SetWatchActions;
  121.     property Directory: widestring read FDirectory write SetDirectory;
  122.     // notification properties. Notify about internal and exernal changes
  123.     property OnNotify: TFileChangeNotifyEvent read FOnNotify write FOnNotify;
  124.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  125.   end;
  126.  
  127. implementation
  128.  
  129. type
  130.   PFILE_NOTIFY_INFORMATION = ^TFILE_NOTIFY_INFORMATION;
  131.   TFILE_NOTIFY_INFORMATION = record
  132.     NextEntryOffset : Cardinal;
  133.     Action          : Cardinal;
  134.     FileNameLength  : Cardinal;
  135.     FileName        : array[0..MAX_PATH - 1] of WideChar;
  136.   end;
  137.  
  138. const
  139.   WM_DIRWATCH_ERROR    = WM_USER + 137;
  140.   WM_DIRWATCH_NOTIFY   = WM_USER + 138;
  141.  
  142.   FILE_LIST_DIRECTORY  = $0001;
  143.  
  144. const
  145.   // error messages
  146.   cErrorInWatchThread = 'Error "%s" in watch thread. Error code: %d';
  147.   cErrorCreateWatchError = 'Error trying to create file handle for "%s". Error code: %d';
  148.  
  149. const
  150.   IO_BUFFER_LEN = 32 * SizeOf(TFILE_NOTIFY_INFORMATION);
  151.  
  152. type
  153.   TDirWatchThread = class(TThread)
  154.   private
  155.      FWatchSubTree : Boolean;
  156.      FAbortEvent   : Cardinal;
  157.      FChangeEvent  : Cardinal;
  158.      FWndHandle    : Cardinal;
  159.      FDirHandle    : Cardinal;
  160.      FDirectory    : widestring;
  161.      FIOResult     : Pointer;
  162.      FFilter       : Integer;
  163.   protected
  164.      procedure Execute; override;
  165.   public
  166.      constructor Create(const Directory: widestring;
  167.                         const WndHandle: Cardinal;
  168.                         const AbortEvent: Cardinal;
  169.                         const TypeFilter: Cardinal;
  170.                         const aWatchSubTree: Boolean);
  171.      destructor Destroy; override;
  172.   end;
  173.  
  174. procedure TDirWatchThread.Execute;
  175. var
  176.   NotifyData: PFILE_NOTIFY_INFORMATION;
  177.   Events: array[0..1] of THandle;
  178.   WaitResult: DWORD;
  179.   NextEntry: Integer;
  180.   ErrorMsg: PWideChar;
  181.   FileName: PWideChar;
  182.   Overlap: TOverlapped;
  183.   ResSize: Cardinal;
  184. begin
  185.   FillChar(Overlap, SizeOf(TOverlapped), 0);
  186.   Overlap.hEvent := FChangeEvent;
  187.  
  188.   // set the array of events
  189.   Events[0] := FChangeEvent;
  190.   Events[1] := FAbortEvent;
  191.  
  192.   while not Terminated do
  193.   try
  194.     if ReadDirectoryChangesW(FDirHandle, FIOResult, IO_BUFFER_LEN, FWatchSubtree, FFilter, @ResSize, @Overlap, nil) then
  195.     begin
  196.       WaitResult := WaitForMultipleObjects(2, @Events[0], FALSE, INFINITE);
  197.  
  198.       // check if we have terminated the thread
  199.       if WaitResult <> WAIT_OBJECT_0 then
  200.       begin
  201.         Terminate;
  202.         Exit;
  203.       end;
  204.      
  205.       if WaitResult = WAIT_OBJECT_0 then
  206.       begin
  207.         NotifyData := FIOResult;
  208.  
  209.         repeat
  210.           NextEntry := NotifyData^.NextEntryOffset;
  211.  
  212.           // get memory for filename and fill it with data
  213.           GetMem(FileName, NotifyData^.FileNameLength + 2);
  214.           Move(NotifyData^.FileName, Pointer(FileName)^, NotifyData^.FileNameLength);
  215.           PWord(Cardinal(FileName) + NotifyData^.FileNameLength)^ := 0;
  216.  
  217.           // send the message about the filename information and advance to the next entry
  218.           PostMessage(FWndHandle, WM_DIRWATCH_NOTIFY, NotifyData^.Action, LParam(FileName));
  219.           Inc(NotifyData, NextEntry);
  220.         until (NextEntry = 0);
  221.       end;
  222.     end;
  223.   except
  224.     on E :Exception do
  225.     begin
  226.       GetMem(ErrorMsg, Length(E.Message) + 2);
  227.       Move(E.Message, Pointer(ErrorMsg)^, Length(E.Message));
  228.       PWord(Cardinal(ErrorMsg) + Cardinal(Length(E.Message)))^ := 0;
  229.       PostMessage(FWndHandle, WM_DIRWATCH_ERROR, GetLastError, LPARAM(ErrorMsg));
  230.     end;
  231.   end;
  232. end;
  233.  
  234. constructor TDirWatchThread.Create(const Directory: widestring;
  235.                                    const WndHandle: Cardinal;
  236.                                    const AbortEvent: Cardinal;
  237.                                    const TypeFilter: Cardinal;
  238.                                    const aWatchSubTree: Boolean);
  239. begin
  240.    //
  241.    // Retrieve proc pointer, open directory to
  242.    // watch and allocate buffer for notification data.
  243.    // (note, it is done before calling inherited
  244.    // create (that calls BeginThread) so any exception
  245.    // will be still raised in caller's thread)
  246.    //
  247.    FDirHandle := CreateFile(PChar(Directory),
  248.                             FILE_LIST_DIRECTORY,
  249.                             FILE_SHARE_READ OR
  250.                             FILE_SHARE_DELETE OR
  251.                             FILE_SHARE_WRITE,
  252.                             nil, OPEN_EXISTING,
  253.                             FILE_FLAG_BACKUP_SEMANTICS OR
  254.                             FILE_FLAG_OVERLAPPED,
  255.                             0);
  256.  
  257.    //if FDirHandle = INVALID_HANDLE_VALUE then
  258.    //begin
  259.    //  raise Exception.CreateFmt(cErrorCreateWatchError, [Directory, GetLastError]);
  260.    //end;
  261.  
  262.    FChangeEvent := CreateEvent(nil, FALSE, FALSE, nil);
  263.    FAbortEvent := AbortEvent;
  264.  
  265.    // allocate the buffer memory
  266.    GetMem(FIOResult, IO_BUFFER_LEN);
  267.  
  268.    FWatchSubTree := aWatchSubtree;
  269.    FWndHandle := WndHandle;
  270.    FDirectory := Directory;
  271.    FFilter := TypeFilter;
  272.  
  273.    // make sure we free the thread
  274.    FreeOnTerminate := True;
  275.  
  276.    inherited Create(False);
  277. end;
  278.  
  279.  
  280. destructor TDirWatchThread.Destroy;
  281. begin
  282.    //if FDirHandle <> INVALID_HANDLE_VALUE  then
  283.    //  FileClose(FDirHandle); { *Konvertiert von CloseHandle* }
  284.    if Assigned(FIOResult) then
  285.      FreeMem(FIOResult);
  286.  
  287.    inherited Destroy;
  288. end;
  289.  
  290. { TFnugryDirWatch }
  291.  
  292. procedure TDirectoryWatch.AllocWatchThread;
  293. begin
  294.   if FWatchThread = nil then
  295.   begin
  296.     FAbortEvent := CreateEvent(nil, FALSE, FALSE, nil);
  297.     FWatchThread := TDirWatchThread.Create(Directory,
  298.                                            FWndHandle,
  299.                                            FAbortEvent,
  300.                                            MakeFilter,
  301.                                            WatchSubtree);
  302.   end;
  303. end;
  304.  
  305. procedure TDirectoryWatch.ReleaseWatchThread;
  306. var
  307.   AResult: Cardinal;
  308. begin
  309.   if FWatchThread <> nil then
  310.   begin
  311.     // set and close event
  312.     SetEvent(FAbortEvent);
  313.     FileClose(FAbortEvent); { *Konvertiert von CloseHandle* }
  314.  
  315.     // wait and block until thread is finished
  316.     AResult := WaitForSingleObject(FWatchThread.Handle, cShutdownTimeout);
  317.  
  318.     // check if we timed out
  319.     if AResult = WAIT_TIMEOUT then
  320.       TerminateThread(FWatchThread.Handle, 0);
  321.  
  322.     FWatchThread := nil;
  323.   end;
  324.  
  325. end;
  326.  
  327. procedure TDirectoryWatch.RestartWatchThread;
  328. begin
  329.   Stop;
  330.   Start;
  331. end;
  332.  
  333. function TDirectoryWatch.Running: Boolean;
  334. begin
  335.   Result := FWatchThread <> nil;
  336. end;
  337.  
  338. procedure TDirectoryWatch.DeallocateHWnd(Wnd: HWND);
  339. var
  340.   Instance: Pointer;
  341. begin
  342.   Instance := Pointer(GetWindowLong(Wnd, GWL_WNDPROC));
  343.  
  344.   if Instance <> @DefWindowProc then
  345.   begin
  346.     { make sure we restore the default
  347.       windows procedure before freeing memory }
  348.     SetWindowLong(Wnd, GWL_WNDPROC, Longint(@DefWindowProc));
  349.     FreeObjectInstance(Instance);
  350.   end;
  351.  
  352.   DestroyWindow(Wnd);
  353. end;
  354.  
  355. destructor TDirectoryWatch.Destroy;
  356. begin
  357.   Stop;
  358.   DeallocateHWnd(FWndHandle);
  359.  
  360.   inherited Destroy;
  361. end;
  362.  
  363. constructor TDirectoryWatch.Create;
  364. begin
  365.    FWndHandle := AllocateHWnd(WatchWndProc);
  366.    FWatchSubtree := True;
  367.  
  368.    // construct the default watch actions and options
  369.    FWatchActions := [waAdded]; //, waRemoved, waModified, waRenamedOld, waRenamedNew];
  370.    FWatchOptions := [woFileName, woDirName, woAttributes, woSize, woLastWrite,
  371.                      woLastAccess, woCreation, woSecurity];
  372. end;
  373.  
  374.  
  375.  
  376. procedure TDirectoryWatch.SetWatchActions(const Value: TWatchActions);
  377. begin
  378.   if FWatchActions <> Value then
  379.   begin
  380.     FWatchActions := Value;
  381.  
  382.     if Running then
  383.       RestartWatchThread;
  384.  
  385.     Change;
  386.   end;
  387. end;
  388.  
  389. procedure TDirectoryWatch.SetWatchOptions(const Value: TWatchOptions);
  390. begin
  391.   if FWatchOptions <> Value then
  392.   begin
  393.     FWatchOptions := Value;
  394.  
  395.     if Running then
  396.       RestartWatchThread;
  397.  
  398.     Change;
  399.   end;
  400. end;
  401.  
  402. procedure TDirectoryWatch.WatchWndProc(var Msg :TMessage);
  403. var
  404.   ErrorCode: Cardinal;
  405.   ErrorMessage: string;
  406. begin
  407.    case Msg.msg of
  408.      WM_DIRWATCH_NOTIFY:
  409.      //
  410.      // Retrieve notify data and forward
  411.      // the event to TDirectoryWatch's notify
  412.      // handler. Free filename string (allocated
  413.      // in WatchThread's notify handler.)
  414.      //
  415.      begin
  416.         try
  417.            Notify(Msg.wParam, WideCharToString(PWideChar(Msg.lParam)));
  418.         finally
  419.           if Msg.lParam <> 0 then
  420.             FreeMem(Pointer(Msg.lParam));
  421.         end;
  422.      end;
  423.  
  424.      WM_DIRWATCH_ERROR:
  425.      //
  426.      // Disable dir watch and re-raise
  427.      // exception on error
  428.      //
  429.      begin
  430.         try
  431.           ErrorMessage := WideCharToString(PWideChar(Msg.lParam));
  432.           ErrorCode := Msg.WParam;
  433.           Stop;
  434.  
  435.           raise Exception.CreateFmt(cErrorInWatchThread, [ErrorMessage, ErrorCode]);
  436.         finally
  437.           if Msg.lParam <> 0 then
  438.             FreeMem(Pointer(Msg.lParam));
  439.         end;
  440.      end;
  441.      //
  442.      // pass all other messages down the line
  443.      //
  444.      else
  445.      begin
  446.        Msg.Result := DefWindowProc(FWndHandle, Msg.Msg, Msg.wParam, Msg.lParam);
  447.        Exit;
  448.      end;
  449.    end;
  450. end;
  451.  
  452. function TDirectoryWatch.MakeFilter: Integer;
  453. const
  454.   FilterFlags: array [TWatchOption] of Integer = (FILE_NOTIFY_CHANGE_FILE_NAME,
  455.                                                   FILE_NOTIFY_CHANGE_DIR_NAME,
  456.                                                   FILE_NOTIFY_CHANGE_ATTRIBUTES,
  457.                                                   FILE_NOTIFY_CHANGE_SIZE,
  458.                                                   FILE_NOTIFY_CHANGE_LAST_WRITE,
  459.                                                   FILE_NOTIFY_CHANGE_LAST_ACCESS,
  460.                                                   FILE_NOTIFY_CHANGE_CREATION,
  461.                                                   FILE_NOTIFY_CHANGE_SECURITY);
  462. var
  463.   Flag: TWatchOption;
  464. begin
  465.   Result := 0;
  466.  
  467.   for Flag in FWatchOptions do
  468.     Result := Result or FilterFlags[Flag];
  469. end;
  470.  
  471. procedure TDirectoryWatch.SetWatchSubTree(const Value :Boolean);
  472. begin
  473.   if Value <> FWatchSubtree then
  474.   begin
  475.     FWatchSubtree := Value;
  476.  
  477.     if Running then
  478.       RestartWatchThread;
  479.  
  480.     Change;
  481.   end;
  482. end;
  483.  
  484.  
  485. procedure TDirectoryWatch.Start;
  486. begin
  487.   if FDirectory = '' then
  488.     raise Exception.Create('Please specify a directory to watch');
  489.  
  490.   if not Running then
  491.   begin
  492.     AllocWatchThread;
  493.     Change;
  494.   end;
  495. end;
  496.  
  497. procedure TDirectoryWatch.Stop;
  498. begin
  499.   if Running then
  500.   begin
  501.     ReleaseWatchThread;
  502.     Change;
  503.   end;
  504. end;
  505.  
  506. procedure TDirectoryWatch.SetDirectory(const Value: widestring);
  507. begin
  508.   if StrIComp(PChar(Trim(Value)), PChar(FDirectory)) <> 0 then
  509.   begin
  510.     FDirectory := Trim(Value);
  511.  
  512.     if Running then
  513.     begin
  514.       RestartWatchThread;
  515.     end;
  516.  
  517.     Change;
  518.   end;
  519. end;
  520.  
  521. procedure TDirectoryWatch.Change;
  522. begin
  523.   if Assigned(FOnChange) then
  524.   begin
  525.     FOnChange(Self);
  526.   end;
  527. end;
  528.  
  529. procedure TDirectoryWatch.Notify(const Action: Integer; const FileName: widestring);
  530. begin
  531.   if Assigned(FOnNotify) then
  532.     if TWatchAction(Action - 1) in FWatchActions then
  533.       FOnNotify(Self, TWatchAction(Action - 1), FileName);
  534. end;
  535.  
  536. end.
  537.  
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on September 05, 2019, 11:00:21 am
I get an Error by using:
"An Error" is a very "clear" statement... Always tell the error message or post a screenshot.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 05, 2019, 11:03:47 am
Screenshot attached but i don't think that this helps much. Because of that i haven't attached it before. And only found this:

Quote
Runtime error 211 program not executable by runtime system
This article explains why a 211 error occurs when trying to run a program that was ported from another server.

Problem:
When I was trying to run a program that was ported from another server, a 211 error occurs. Specifically, the message received was a load error 211 pc=0, call=1, seg=20 211 program not executable by runtime system. Why is this happening?

Resolution:
The reason this error is occurring is because the program is 64 bit and was ported over from another system to one whose Server Express product and/or hardware is 32 bit only. This problem can occur on AIX systems with Server Express prior to version 4.0SP2. The 32 and 64 bit versions for AIX were separate products until version 4.0SP2 was released. If a program is compiled with the 64 bit product on an AIX system and run with COBDIR, PATH, and LIBPATH set for the 32 bit product, error 211 will occur. The same is true for 64 bit code ported to any AIX 4.3.3 system. That version of AIX is 32 bit only. A few Sun Solaris installations run on 32 bit-only SPARC hardware. Load error 211 will occur if a 64 bit program is ported from another Solaris/SPARC system. Object Cobol Developer Suite is 32 bit only on all platforms and cannot run 64 bit programs.

Incident Number: 2146320

Old KB# 14397
Title: Re: Convert Errors Delphi -> Lazarus
Post by: avra on September 05, 2019, 11:50:14 am
Runtime error 211:
Quote
Call to abstract method
Your program tried to execute an abstract virtual method. Abstract methods should be overridden, and the overriding method should be called.
https://www.freepascal.org/docs-html/user/userap4.html
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 05, 2019, 12:15:12 pm
Ok, thats new to me where / how i have to override this?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on September 05, 2019, 12:20:14 pm
When want to know what an error number means I always search for "Lazarus runtime error", and this leads me to https://www.freepascal.org/docs-html/user/userap4.html at the top of the list. When you scroll down and find error 211, there is:
Quote
211 Call to abstract method
    Your program tried to execute an abstract virtual method. Abstract methods should be overridden, and the overriding method should be called.

An abstract method is a method introduced by an ancestor in the class hierarchy which only provides its name but has no implementation; its declaration is marked as "abstract". There must always be a derived class which implements the method. An attempt to create an instance of the ancestor class (which introduced the abstract method first) raises the 211 error. You only can call the overridden method of the derived class.

The only abstract method which comes to my mind in relation to your code is the TThread.Execute, but this is overridden by your TDirWatchThread.Execute. Unfortunately some external units are called there which I do not have. I commented the inner part of the Execute method and could compile a demo which simply creates a TDirWatcher. Like you I am getting a runtime error, but now it is 217 ("unhandled exception"). Debugging deeper shows that TDirWatcher.Create calls AllocateHWnd, but CTRL-clicking onto this identifier shows that this does not seem to be implemented by FPC:

Code: Pascal  [Select]
  1. function AllocateHWnd(Method: TWndMethod): HWND;  // in classes.pp
  2.   begin
  3.     { dummy }
  4.     runerror(217);
  5.     Result:=0;
  6.   end;

Therefore, I guess that it is not possible to convert the TDirWatcher to Lazarus without changes in its inner structure. Of course, this requires deep knowledge of what the component is doing and how it is working.

Maybe there is a ready-made component for Lazarus which has a similar functionality and which you can use for the TDirWatcher instead.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 05, 2019, 12:35:15 pm
The Watcher is only used wo see if there is a new (txt) file created and then if it has been edited. If there are no changes to this file do something.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on September 05, 2019, 01:00:01 pm
Typing "lazarus directory watcher" into "my" search engine brings me to https://forum.lazarus.freepascal.org/index.php?topic=37371.0, and this leads me to http://www.angusj.com/delphi/dirwatch.html. The DirWatch component discussed here is for Delphi, but just looking at the units in the uses clause tell that it should be easily ported to Lazarus. Maybe you should try this one as a replacement.

[EDIT]
No... I tried to port it, but ran into the same problem. It calls AllocateHWnd, too.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Xor-el on September 05, 2019, 01:54:36 pm
Here is a directory watcher for Lazarus which is cross platform.

https://forum.lazarus.freepascal.org/index.php?topic=37415.0 (https://forum.lazarus.freepascal.org/index.php?topic=37415.0)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on September 05, 2019, 05:09:33 pm
Here is a directory watcher for Lazarus which is cross platform.

https://forum.lazarus.freepascal.org/index.php?topic=37415.0 (https://forum.lazarus.freepascal.org/index.php?topic=37415.0)

Yes, and the only good one as well, much better that the old Angus Johnson code.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 06, 2019, 09:10:05 am
Hmm, i am working on to change it in lazarus now but i am missing a "stop" and/or "destroy" command. I am only able to create and to start it but i don't want to create more than one a time.
Normally i do it as following:
Button pressed and conditions met -> Create Watcher (set path and only when file is added) and start it.
When the watcher has noticed the new file in the directory -> stop and destroy the watcher and some more things todo.

But when i create the watcher everytime, and never destroy or stop it, i would have multiple watcher active.

Additionally i am not sure, how to implement it correct because the "demo" seem to work different.

Title: Re: Convert Errors Delphi -> Lazarus
Post by: Thaddy on September 06, 2019, 09:25:22 am
Use class methods to prevent that. Easy. That's also compaible with "newer" (d2005) delphi code.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 06, 2019, 09:59:37 am
Hmm, sorry i didn't work with class methods for now. The code in witch the watcher is used see below. How to change this to directory watcher for Lazarus?

When i am right i have to change the procedure "NewLog" to a class method right? But how to stop the watcher from the Button (EscapeClick) or when it found a file? And i need the filename!

Code: Pascal  [Select]
  1.   private
  2.     { Private-Deklarationen }
  3.     Watch: TDirectoryWatch;
  4.     procedure OnNotify(const Sender: TObject; const Action: TDirectoryEventType; const FileName: widestring);
  5.  
  6. //Cancel searching for new logfile
  7. procedure TTools.EscapeClick(Sender: TObject);
  8. var
  9.   List         : TList;
  10.   I, answer    : Integer;
  11.   ProcessId    : DWORD;
  12.   ThreadId     : DWORD;
  13.   ProcessHandle: THandle;
  14.   ExitCode     : DWORD;
  15. begin
  16.   if Instant.Enabled = true then
  17.   begin
  18.     answer := messagedlg('Wollen sie wirklich abbrechen?', mtConfirmation, [mbYes,mbNo], 0);
  19.     if answer = mrYes then
  20.     begin
  21.       //Some Switches to set
  22.     end;
  23.   end else
  24.   begin
  25.     //Some Switches to set
  26.     Watch.Stop; //Stop Watcher here
  27.   end;
  28. end;
  29.  
  30. //Begin to search Log-File
  31. procedure TTools.NewLog(Path : string);
  32. begin
  33. if FileAction = 'Create' then
  34.   if System.SysUtils.ForceDirectories(Path) then
  35.     begin
  36.       //Some Switches to set
  37.       Watch                      := TDirectoryWatch.Create;  //Create Watcher and set properties
  38.       Watch.WatchOptions := [woCreation];
  39.       Watch.WatchActions := [waAdded];
  40.       Watch.Directory       := Path;
  41.       Watch.OnNotify        := OnNotify;
  42.       Watch.Start;                                                       //Start Watcher
  43.     end else
  44.     begin
  45.       MessageDlg('Verzeichnis konnte nicht erstellt werden.', TMsgDlgType.mtError, [mbOK], 0);
  46.     end;
  47. else if FileAction = 'Edited' then
  48.   begin
  49.     //Some Switches to set
  50.   end;
  51. end;
  52.  
  53. //Found the Log-File
  54. procedure TTools.OnNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string);
  55. begin
  56.   if (Split(FileName, '2', 0) = 'Log') or
  57.      (Split(FileName, '2', 0) = 'log') then
  58.   begin
  59.     case Action of
  60.       waAdded:  begin
  61.                   //Some Switches to set
  62.                   Watch.Stop;                  //Stop and destroy the Watcher
  63.                   Watch.Destroy;
  64.                   //Some Switches to set
  65.                 end;
  66.       waRemoved: ;
  67.       waModified: ;
  68.     end;
  69.   end;
  70. end;
  71.  

I changed it as following but still filename and stop/ destroy command is missing to me:

Code: Pascal  [Select]
  1. private
  2.     { Private-Deklarationen }
  3.     Watch                        : IDirectoryWatcher;
  4.     procedure OnNotify(const FilePath: WideString; const Action: TDirectoryEventType);
  5.  
  6. //Cancel searching for new logfile
  7. procedure TTools.EscapeClick(Sender: TObject);
  8. var
  9.   List         : TList;
  10.   I, answer    : Integer;
  11.   ProcessId    : DWORD;
  12.   ThreadId     : DWORD;
  13.   ProcessHandle: THandle;
  14.   ExitCode     : DWORD;
  15. begin
  16.   if Instant.Enabled = true then
  17.   begin
  18.     answer := messagedlg('Wollen sie wirklich abbrechen?', mtConfirmation, [mbYes,mbNo], 0);
  19.     if answer = mrYes then
  20.     begin
  21.       //Some Switches to set
  22.     end;
  23.   end else
  24.   begin
  25.     //Some Switches to set
  26.     //Watch.Stop; //Stop Watcher here - removed now but is still a must be!!
  27.   end;
  28. end;
  29.  
  30. //Begin to search Log-File
  31. procedure TTools.NewLog(Path : string);
  32. begin
  33. if FileAction = 'Create' then
  34.   if System.SysUtils.ForceDirectories(Path) then
  35.     begin
  36.       //Some Switches to set
  37.       Watch              := TDirectoryWatcherBuilder.New
  38.                                                       .WatchDirectory(Path)
  39.                                                       .Recursively(False)
  40.                                                       .OnChangeTrigger(OnNotify)
  41.                                                       .Build;
  42.         Watch.Start;                                                      //Start Watcher
  43.     end else
  44.     begin
  45.       MessageDlg('Verzeichnis konnte nicht erstellt werden.', TMsgDlgType.mtError, [mbOK], 0);
  46.     end;
  47. else if FileAction = 'Edited' then
  48.   begin
  49.     //Some Switches to set
  50.   end;
  51. end;
  52.  
  53. //Found the Log-File
  54. procedure TTools.OnNotify(const FilePath: WideString; const Action: TDirectoryEventType);
  55. var
  56.   start, i : integer;
  57.   FileName : String;
  58. begin
  59.   FileName := '';
  60.   for i := length(FilePath) downto 1 do
  61.   begin
  62.     if FilePath[i] = '\' then
  63.     begin
  64.       start := i + 1;
  65.       break;
  66.     end;
  67.   end;
  68.   for i := start to length(FilePath) do
  69.   begin
  70.     FileName := FileName + FilePath[i];    //-Error: SuspendThread failed. (winerr 6)
  71.   end;  
  72.   if (Split(FileName, '2', 0) = 'Log') or
  73.      (Split(FileName, '2', 0) = 'log') then
  74.   begin
  75.     case Action of
  76.       waAdded:  begin
  77.                   //Some Switches to set
  78.                   //Watch.Stop;                      //Stop Watcher here - removed now but is still a must be!!
  79.                   //Watch.Destroy;                 //Destroy Watcher here - removed now but is still a must be!!
  80.                   //Some Switches to set
  81.                 end;
  82.       waRemoved: ;
  83.       waModified: ;
  84.     end;
  85.   end;
  86. end;
  87.  
Title: Re: Convert Errors Delphi -> Lazarus
Post by: wp on September 06, 2019, 11:07:25 am
But when i create the watcher everytime, and never destroy or stop it, i would have multiple watcher active.
Why don't you initialize the watcher with nil and create it only when it is not nil? Then, when you want to stop it, you destroy it and set it back to nil (FreeAndNil(Watch)). This way it is prevented to have multiple watchers.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 06, 2019, 11:21:57 am
You are right, didn't think of freeandnil()  :-[
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 17, 2019, 04:08:10 pm
So, got most to work but here i don't know why its not going on:
Code: Pascal  [Select]
  1. //Dateizeit ausgeben
  2. function TTools.ReportFileTimes(const FileName: WideString) : TDateTime;
  3.  
  4.   procedure ReportTime(const Name: string; const FileTime: TFileTime);
  5.   var
  6.     SystemTime, LocalTime: TSystemTime;
  7.   begin
  8.     if not FileTimeToSystemTime(FileTime, SystemTime) then
  9.     begin
  10.       ShowMessage(SysErrorMessage(GetLastError));
  11.     end;
  12.     if not SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime) then
  13.     begin
  14.       ShowMessage(SysErrorMessage(GetLastError));
  15.     end;
  16.     result := SystemTimeToDateTime(LocalTime);
  17.   end;
  18.  
  19. var
  20.   fad: TWin32FileAttributeData;
  21. begin
  22.   if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
  23.   begin
  24.     ShowMessage(SysErrorMessage(GetLastError));  //Error: The system can't find the file. But Path is correct and file is still there (C:\Software\Installation\Win_version\log1321313131.txt)
  25.   end;
  26.   ReportTime('Modified', fad.ftLastWriteTime);
  27. end;
  28.  

Called as:
Code: Pascal  [Select]
  1. LogA.Caption    := DateToStr(ReportFileTimes(LogName));
  2.  

When i use to check

ShowMessage(String(FileName));
 
Filename is correct but when i use:

ShowMessage(String(PChar(FileName))); 

Filename is only "C".

Anyone an idea?
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Cyrax on September 17, 2019, 04:25:21 pm
So, got most to work but here i don't know why its not going on:
Code: Pascal  [Select]
  1. //Dateizeit ausgeben
  2. function TTools.ReportFileTimes(const FileName: WideString) : TDateTime;
  3.  
  4.   procedure ReportTime(const Name: string; const FileTime: TFileTime);
  5.   var
  6.     SystemTime, LocalTime: TSystemTime;
  7.   begin
  8.     if not FileTimeToSystemTime(FileTime, SystemTime) then
  9.     begin
  10.       ShowMessage(SysErrorMessage(GetLastError));
  11.     end;
  12.     if not SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime) then
  13.     begin
  14.       ShowMessage(SysErrorMessage(GetLastError));
  15.     end;
  16.     result := SystemTimeToDateTime(LocalTime);
  17.   end;
  18.  
  19. var
  20.   fad: TWin32FileAttributeData;
  21. begin
  22.   if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then
  23.   begin
  24.     ShowMessage(SysErrorMessage(GetLastError));  //Error: The system can't find the file. But Path is correct and file is still there (C:\Software\Installation\Win_version\log1321313131.txt)
  25.   end;
  26.   ReportTime('Modified', fad.ftLastWriteTime);
  27. end;
  28.  

Called as:
Code: Pascal  [Select]
  1. LogA.Caption    := DateToStr(ReportFileTimes(LogName));
  2.  

When i use to check

ShowMessage(String(FileName));
 
Filename is correct but when i use:

ShowMessage(String(PChar(FileName))); 

Filename is only "C".

Anyone an idea?

Remove explicit conversion to PChar type.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 18, 2019, 07:55:21 am
Sorry but i have to use PChar here:

GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad)

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I understand that the system can't find the file when the file/path is not given correctly when using PChar here. So what i am doing wrong here in Lazaraus?

I changed it now to

GetFileAttributesEx(PChar(String(FileName)), GetFileExInfoStandard, @fad)

and don't get an error message now -.-
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Cyrax on September 18, 2019, 08:11:56 am
Sorry but i have to use PChar here:

GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad)

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I understand that the system can't find the file when the file/path is not given correctly when using PChar here. So what i am doing wrong here in Lazaraus?

Code: Pascal  [Select]
  1. ShowMessage(String(PChar(FileName)));

You don't need the conversion here.
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Moombas on September 18, 2019, 08:40:30 am
Sorry but i have to use PChar here:

GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad)

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I understand that the system can't find the file when the file/path is not given correctly when using PChar here. So what i am doing wrong here in Lazaraus?

Code: Pascal  [Select]
  1. ShowMessage(String(PChar(FileName)));

You don't need the conversion here.

Please read completely:

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I solved this problem by this:

GetFileAttributesEx(PChar(String(FileName)), GetFileExInfoStandard, @fad)
Title: Re: Convert Errors Delphi -> Lazarus
Post by: Cyrax on September 18, 2019, 08:51:40 am
Sorry but i have to use PChar here:

GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad)

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I understand that the system can't find the file when the file/path is not given correctly when using PChar here. So what i am doing wrong here in Lazaraus?

Code: Pascal  [Select]
  1. ShowMessage(String(PChar(FileName)));

You don't need the conversion here.

Please read completely:

Following is only to test if the data is given correctly:

ShowMessage(String(PChar(FileName))); 

I solved this problem by this:

GetFileAttributesEx(PChar(String(FileName)), GetFileExInfoStandard, @fad)

Okay then. Have it you way. O:-)