Recent

Author Topic: Convert Errors Delphi -> Lazarus  (Read 2836 times)

avra

  • Hero Member
  • *****
  • Posts: 1690
    • Additional info
Re: Convert Errors Delphi -> Lazarus
« Reply #45 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
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #46 on: September 05, 2019, 12:15:12 pm »
Ok, thats new to me where / how i have to override this?
The path is the destination but you should never lose sight of the destination on the way.

wp

  • Hero Member
  • *****
  • Posts: 6235
Re: Convert Errors Delphi -> Lazarus
« Reply #47 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.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #48 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.
The path is the destination but you should never lose sight of the destination on the way.

wp

  • Hero Member
  • *****
  • Posts: 6235
Re: Convert Errors Delphi -> Lazarus
« Reply #49 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.
« Last Edit: September 05, 2019, 01:31:54 pm by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Xor-el

  • Sr. Member
  • ****
  • Posts: 371
Re: Convert Errors Delphi -> Lazarus
« Reply #50 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

Thaddy

  • Hero Member
  • *****
  • Posts: 8967
Re: Convert Errors Delphi -> Lazarus
« Reply #51 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

Yes, and the only good one as well, much better that the old Angus Johnson code.
Most people that want to use threading should learn to patch their jeans first: use a needle.

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #52 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.

« Last Edit: September 06, 2019, 09:33:26 am by Moombas »
The path is the destination but you should never lose sight of the destination on the way.

Thaddy

  • Hero Member
  • *****
  • Posts: 8967
Re: Convert Errors Delphi -> Lazarus
« Reply #53 on: September 06, 2019, 09:25:22 am »
Use class methods to prevent that. Easy. That's also compaible with "newer" (d2005) delphi code.
Most people that want to use threading should learn to patch their jeans first: use a needle.

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #54 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.  
« Last Edit: September 06, 2019, 03:06:48 pm by Moombas »
The path is the destination but you should never lose sight of the destination on the way.

wp

  • Hero Member
  • *****
  • Posts: 6235
Re: Convert Errors Delphi -> Lazarus
« Reply #55 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.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #56 on: September 06, 2019, 11:21:57 am »
You are right, didn't think of freeandnil()  :-[
« Last Edit: September 12, 2019, 07:53:45 am by Moombas »
The path is the destination but you should never lose sight of the destination on the way.

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #57 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?
« Last Edit: September 17, 2019, 04:10:04 pm by Moombas »
The path is the destination but you should never lose sight of the destination on the way.

Cyrax

  • Hero Member
  • *****
  • Posts: 755
Re: Convert Errors Delphi -> Lazarus
« Reply #58 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.

Moombas

  • New Member
  • *
  • Posts: 24
Re: Convert Errors Delphi -> Lazarus
« Reply #59 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 -.-
« Last Edit: September 18, 2019, 08:17:31 am by Moombas »
The path is the destination but you should never lose sight of the destination on the way.