Recent

Author Topic: Help with tsearchrec  (Read 1596 times)

SteveSS

  • New Member
  • *
  • Posts: 43
Help with tsearchrec
« on: March 21, 2023, 11:37:50 am »
I am trying to convert some Delphi code to Lazarus.  It uses tsearchrec.finddata.ftlastwritetime.  This does not compile  - the error message for the line is 'got filetime expected tdatetime'.

I have looked at the documentation but can't find any help (probably looking in the wrong place as usual).  Any help for this please?  What I am really looking for its the Date Taken value - I am dealing with digital photographs - .jpg format.

Steve

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2007
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Help with tsearchrec
« Reply #1 on: March 21, 2023, 12:00:19 pm »
Code: Pascal  [Select][+][-]
  1. type
  2.   ULONGLONG  = UInt64;
  3.   ULARGE_INTEGER = record
  4.      case byte of
  5.        0: (LowPart : DWORD;
  6.            HighPart : DWORD);
  7.        1: (QuadPart : ULONGLONG);
  8.     end;
  9.   FILETIME = record
  10.        dwLowDateTime : DWORD;
  11.        dwHighDateTime : DWORD;
  12.     end;
  13.  
  14. function FileTimeToDateTime(AFileTime: FILETIME): TDateTime;
  15. var
  16.     li: ULARGE_INTEGER;
  17. const
  18.     OA_ZERO_TICKS = UInt64(94353120000000000);
  19.     TICKS_PER_DAY = UInt64(864000000000);
  20. begin
  21.     li.LowPart := AFileTime.dwLowDateTime;
  22.     li.HighPart := AFileTime.dwHighDateTime;
  23.     Result := (Real(li.QuadPart) - OA_ZERO_TICKS) / TICKS_PER_DAY;
  24. end;
  25.  
  26. function DateTimeToFileTime(ADateTimeUTC: TDateTime): FILETIME;
  27. var
  28.     li: ULARGE_INTEGER;
  29. const
  30.     OA_ZERO_TICKS = UInt64(94353120000000000);
  31.     TICKS_PER_DAY = UInt64(864000000000);
  32. begin
  33.     li.QuadPart := Round(ADateTimeUtc*TICKS_PER_DAY + OA_ZERO_TICKS);
  34.     Result.dwLowDateTime := li.LowPart;
  35.     Result.dwHighDateTime := li.HighPart;
  36. end;

Does that help you?
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

SteveSS

  • New Member
  • *
  • Posts: 43
Re: Help with tsearchrec
« Reply #2 on: March 21, 2023, 12:22:35 pm »
Thanks for the reply but it doesn't really help.  Just to give a bit more detail of what I am trying to do,  I download photos from my digital camera into a standard directory.  These are called IMG_1234, IMG_1235 etc.  What the software needs to do is access each file in turn and re-name the file to Dddmmss.jpg where ddmmss is the date/time the photo was taken.  The file is then saved to a pre-determined directory
C:\Photos\yyyy\month e.g \2023\03-March where they will appear in date/time taken order.

All I need is  the tsearchrec field name available to get hold of the date / time taken.  If you right click on a jpg file the date time taken is in the details tab.

Steve

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Help with tsearchrec
« Reply #3 on: March 21, 2023, 12:40:26 pm »
The date taken field is not necessarily the lastmodified time.

Such extended properties are only determined by examining the file (looking inside the JPG), and not part of the directory structure.

So while the explorer retrieves it via other systems, the base windows api does not.

The easiest is to load this from the EXIF metadata with libraries like fpexif


SteveSS

  • New Member
  • *
  • Posts: 43
Re: Help with tsearchrec
« Reply #4 on: March 21, 2023, 01:47:36 pm »
Thanks markov but I wouldn't have a clue where to start with that.  I think we are getting over complicated -
the delphi code is :

      created  := FileTimeToDateTime(SearchRec.FindData.ftLastWriteTime);

created is a tdatetime.

All I want is the lazarus equivalent but preferably with fttimetaken (if it exists).

Steve

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Help with tsearchrec
« Reply #5 on: March 21, 2023, 01:47:45 pm »
The functions KodeZwerg wrote are superfluous, since https://www.freepascal.org/docs-html/rtl/sysutils/filedatetodatetime.html and the likes are already in sysutils and also take time into account.
But for correct info, indeed better to read the EXIF data (if any) as Marcov wrote.

In case there maybe a small issue with your last line of code:
Code: Pascal  [Select][+][-]
  1.  created  := FileDateToDateTime(SearchRec.FindData.ftLastWriteTime);
means the exact same thing as in Delphi.
If it is not there in sysutils, I will provide a patch for an alias.
( I don't think you want just the time information and throw the date part away! and even that is easily fixed.)
« Last Edit: March 21, 2023, 01:53:28 pm by Thaddy »
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Help with tsearchrec
« Reply #6 on: March 21, 2023, 02:06:53 pm »
I tried, but no, it doesn't work that way. I converted the filetime to a quad using part of Kodezwerg's code, and then used filedatetodatetime, but apparently that is not the same.

Stranger though, SteveSS' code is not compiled by Delphi either.  It doesn't know filetimetodatetime either.

balazsszekely

  • Guest
Re: Help with tsearchrec
« Reply #7 on: March 21, 2023, 02:16:26 pm »
Try something like this(not tested):

Code: Pascal  [Select][+][-]
  1. uses windows;
  2.  
  3. function GetFileTime(AFileTime: TFileTime; out ADateTime: TDateTime): Boolean;
  4. var
  5.   LocalFileTime: TFileTime;
  6.   SystemTime: TSystemTime;
  7. begin
  8.   Result := False;
  9.   if FileTimeToLocalFileTime(AFileTime, LocalFileTime) then
  10.   begin
  11.     if FileTimeToSystemTime(LocalFileTime, SystemTime) then
  12.     begin
  13.        ADateTime:= SystemTimeToDateTime(SystemTime);
  14.        Result := True;
  15.     end;
  16.   end;
  17. end;
  18.  
  19. procedure TForm1.Button1Click(Sender: TObject);
  20. var
  21.   DateTime: TDateTime;
  22.   SR: TSearchRec;
  23. begin
  24.    if FindFirst('d:\test\SomeFile.txt', faAnyFile, SR) = 0 then //<- change it here
  25.      if GetFileTime(SR.FindData.ftLastWriteTime, DateTime) then
  26.         ShowMessage(FormatDateTime('YYYY.MM.DD hh:mm:ss', DateTime));
  27. end;
  28.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Help with tsearchrec
« Reply #8 on: March 21, 2023, 02:35:56 pm »
I tried, but no, it doesn't work that way. I converted the filetime to a quad using part of Kodezwerg's code, and then used filedatetodatetime, but apparently that is not the same.

Stranger though, SteveSS' code is not compiled by Delphi either.  It doesn't know filetimetodatetime either.
Again, stranger is that the example code in the manual (Ex13.pp) alone is enough to fix Steve's problem.
Specialize a type, not a var.

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Help with tsearchrec
« Reply #9 on: March 21, 2023, 07:23:33 pm »
Hello Steve,

you are on Windows, correct?

Which FPC-Version do you use? Date-Time-things in 'tsearchrec' have changed during the last versions.

SteveSS

  • New Member
  • *
  • Posts: 43
Re: Help with tsearchrec
« Reply #10 on: March 28, 2023, 11:19:18 am »
Sorry for the delay.  Yes - Windows 10, Lazarus 1.8.4.  Can I ask a slightly different question ... when you hover the mouse over a .jpg image it shows (among other things) the date taken in dd/mm/yyyy hh.mm format.  All I want to do is extract the date / time in lazarus code.

Steve

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Help with tsearchrec
« Reply #11 on: March 28, 2023, 11:35:13 am »
And I explained to you that that date is INSIDE the jpg file, and not in the attributes parsable with findfirst/findnext.

For those you need to use fpexif or gdiplus as per https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-reading-and-writing-metadata-use

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2007
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Help with tsearchrec
« Reply #12 on: March 28, 2023, 01:30:38 pm »
I am still a little bit confused, so here is another way to retrieve, if stored, the times for a file.
Maybe it help to clarify what you really want to get:
Code: Pascal  [Select][+][-]
  1. uses Windows;
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4.   function FileTimeToLocalSystemTime(const FileTime: TFileTime): TSystemTime;
  5.   var
  6.     LocalTime: TFileTime;
  7.   begin
  8.     try
  9.       FileTimeToLocalFileTime(FileTime, LocalTime);
  10.     finally
  11.       FileTimeToSystemTime(LocalTime, Result);
  12.     end;
  13.   end;
  14.   function FileTimeToDateTime(const FileTime: TFileTime): TDateTime;
  15.   var
  16.     SystemTime: TSystemTime;
  17.   begin
  18.     try
  19.       SystemTime := FileTimeToLocalSystemTime(FileTime);
  20.     finally
  21.       with SystemTime do
  22.         Result := EncodeDate(wYear, wMonth, wDay) + EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
  23.     end;
  24.   end;
  25.   function FileTimeToStr(const FileTime: TFileTime): string;
  26.   var
  27.     DateTime: TDateTime;
  28.   begin
  29.     try
  30.       DateTime := FileTimeToDateTime(FileTime);
  31.     finally
  32.       Result   := DateTimeToStr(DateTime);
  33.     end;
  34.   end;
  35. type
  36.   TTimeStr = packed record
  37.     Creation,
  38.     Access,
  39.     Written: string;
  40.   end;
  41. var
  42.   hFindFile: THandle;
  43.   FindData: TWin32FindData;
  44.   sPath: string;
  45.   TimeStr: TTimeStr;
  46. begin
  47.   if OpenDialog1.Execute then
  48.     begin
  49.       sPath := OpenDialog1.FileName;
  50.       hFindFile := Windows.FindFirstFile(PChar(sPath), FindData);
  51.       if (hFindFile <> INVALID_HANDLE_VALUE) then
  52.         begin
  53.           TimeStr.Creation := FileTimeToStr(FindData.ftCreationTime);
  54.           TimeStr.Access   := FileTimeToStr(FindData.ftLastAccessTime);
  55.           TimeStr.Written  := FileTimeToStr(FindData.ftLastWriteTime);
  56.           Windows.FindClose(hFindFile);
  57.           Memo1.Lines.BeginUpdate;
  58.           Memo1.Clear;
  59.           Memo1.Lines.Add('File: ' + sPath);
  60.           Memo1.Lines.Add('Access: ' + TimeStr.Access);
  61.           Memo1.Lines.Add('Creation: ' + TimeStr.Creation);
  62.           Memo1.Lines.Add('Written: ' + TimeStr.Written);
  63.           Memo1.Lines.EndUpdate;
  64.       end;
  65.     end;
  66. end;
If your needed time is not shown up with above way, than use what marcov told.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

paweld

  • Hero Member
  • *****
  • Posts: 970
Re: Help with tsearchrec
« Reply #13 on: March 28, 2023, 10:54:09 pm »
Example attached - use TFileSearcher and fpexif
Best regards / Pozdrawiam
paweld

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Help with tsearchrec
« Reply #14 on: March 29, 2023, 07:30:22 pm »
Stranger though, SteveSS' code is not compiled by Delphi either.  It doesn't know filetimetodatetime either.

There is no FileTimeToDateTime() function in Delphi, so it must have been a custom function in whatever project that code was taken from.  There is a FileDateToDateTime() function in the SysUtils unit, but you can't pass SearchRec.FindData.ftLastWriteTime to it, you would have to pass in SearchRec.Time instead.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018