WIN32_FIND_DATA structure

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

WIN32_FIND_DATA structure

Post by jNizM » 28 Jul 2020, 07:30

Moin,

konnte auf der schnelle kein sinnvollen Eintrag hier im Forum dazu finden.

Hat jemand schon mal sich mit der WIN32_FIND_DATA structure auseinander gesetzt?
WIN32_FIND_DATAA structure & WIN32_FIND_DATAW structure

Wird hauptsächlich für InternetFindNextFileA /W / FtpFindFirstFileA / W und InternetFindNextFileA / W benutzt

Im Forum finde ich die diversesten Strukturgrößen (z.B. 1140 usw.), die alle eigtl nicht stimmen können.
Mit dem sizeofchecker bekomme ich fogendes zurück:
WIN32_FIND_DATAA -> 320
WIN32_FIND_DATAW -> 592
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 28 Jul 2020, 07:38

Code: Select all

typedef struct _WIN32_FIND_DATAA {
    DWORD dwFileAttributes;										// UInt							4
    FILETIME ftCreationTime;									// Ptr		-> UInt / UInt		8
    FILETIME ftLastAccessTime;									// Ptr		-> UInt / UInt		8
    FILETIME ftLastWriteTime;									// Ptr		-> UInt / UInt		8
    DWORD nFileSizeHigh;										// UInt							4
    DWORD nFileSizeLow;											// UInt							4
    DWORD dwReserved0;											// UInt							4
    DWORD dwReserved1;											// UInt							4
    _Field_z_ CHAR   cFileName[ MAX_PATH ];						// Char							260
    _Field_z_ CHAR   cAlternateFileName[ 14 ];					// Char							14
#ifdef _MAC
    DWORD dwFileType;
    DWORD dwCreatorType;
    WORD  wFinderFlags;
#endif
} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA;

Code: Select all

typedef struct _WIN32_FIND_DATAW {
    DWORD dwFileAttributes;										// UInt							4
    FILETIME ftCreationTime;									// Ptr		-> UInt / UInt		8
    FILETIME ftLastAccessTime;									// Ptr		-> UInt / UInt		8
    FILETIME ftLastWriteTime;									// Ptr		-> UInt / UInt		8
    DWORD nFileSizeHigh;										// UInt							4
    DWORD nFileSizeLow;											// UInt							4
    DWORD dwReserved0;											// UInt							4
    DWORD dwReserved1;											// UInt							4
    _Field_z_ WCHAR  cFileName[ MAX_PATH ];						// UShort						260 * 2
    _Field_z_ WCHAR  cAlternateFileName[ 14 ];					// UShort						14 * 2
#ifdef _MAC
    DWORD dwFileType;
    DWORD dwCreatorType;
    WORD  wFinderFlags;
#endif
} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

swagfag
Posts: 4008
Joined: 11 Jan 2017, 17:59

Re: WIN32_FIND_DATA structure

Post by swagfag » 28 Jul 2020, 08:40

Code: Select all

_WIN32_FIND_DATAA
{
	[  0] UInt dwFileAttributes
	[  4] UInt ftCreationTime.dwLowDateTime
	[  8] UInt ftCreationTime.dwHighDateTime
	[ 12] UInt ftLastAccessTime.dwLowDateTime
	[ 16] UInt ftLastAccessTime.dwHighDateTime
	[ 20] UInt ftLastWriteTime.dwLowDateTime
	[ 24] UInt ftLastWriteTime.dwHighDateTime
	[ 28] UInt nFileSizeHigh
	[ 32] UInt nFileSizeLow
	[ 36] UInt dwReserved0
	[ 40] UInt dwReserved1
	[ 44] Char cFileName[ 260 ]
	[304] Char cAlternateFileName[ 14 ]
	[318] Char paddingbytes[ 2 ]
}

just me
Posts: 7287
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: WIN32_FIND_DATA structure

Post by just me » 29 Jul 2020, 06:12

Moin,

nur ein ergänzender Hinweis:

Die FILETIME Struktur enthält zwei DWORD / UInt Felder a 4 Bytes. Das ergibt zwar mit 8 Bytes auf 64-Bit Systemen zusammen einen Speicherbereich in Pointergröße, es ist aber kein Ptr Typ. (Die Ausrichtung lässt grüßen!)

Die Werte aus Deinem sizeofchecker stimmen (siehe swagfag's paddingbytes).

Viel Spaß noch!

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 29 Jul 2020, 06:26

Moin,

soweit habe ich das zzt. nur sind die Rüggabewerte noch etwas mau. Muss noch mehr testen.

Code: Select all

...

	FindFirstFile(hConnect, ByRef hFind, SearchFile := "*.*", TimeFormat := "system", SizeFormat := "auto", SizeSuffix := false)
	{
		VarSetCapacity(WIN32_FIND_DATA, (A_IsUnicode ? 592 : 320), 0)
		if (hFind := DllCall("wininet\FtpFindFirstFile", "ptr", hConnect, "str", SearchFile, "ptr", &WIN32_FIND_DATA, "uint", 0, "uint*", 0))
			return this.FindData(&WIN32_FIND_DATA, TimeFormat, SizeFormat, SizeSuffix)
		VarSetCapacity(WIN32_FIND_DATA, 0)
		return false
	}


	FindNextFile(hFind)
	{
		VarSetCapacity(WIN32_FIND_DATA, (A_IsUnicode ? 592 : 320), 0)
		if (DllCall("wininet\InternetFindNextFile", "ptr", hFind, "ptr", &WIN32_FIND_DATA))
			return this.FindData(&WIN32_FIND_DATA, TimeFormat, SizeFormat, SizeSuffix)
		VarSetCapacity(WIN32_FIND_DATA, 0)
		return false
	}


	FindData(WIN32_FIND_DATA, TimeFormat := "system", SizeFormat := "auto", SizeSuffix := false)
	{
		static MAX_PATH := 260
		static MAXDWORD := 0xffffffff

		addr := &WIN32_FIND_DATA
		FIND_DATA := []
		FIND_DATA["FileAttributes"]    := "test"
		FIND_DATA["CreationTime"]      := this.FileTime(   NumGet(addr +  4, "uint") << 32 | NumGet(addr +  8, "uint"), TimeFormat)
		FIND_DATA["LastAccessTime"]    := this.FileTime(   NumGet(addr + 12, "uint") << 32 | NumGet(addr + 16, "uint"), TimeFormat)
		FIND_DATA["LastWriteTime"]     := this.FileTime(   NumGet(addr + 20, "uint") << 32 | NumGet(addr + 24, "uint"), TimeFormat)
		FIND_DATA["FileSize"]          := this.FormatBytes((NumGet(addr + 28, "uint") * (MAXDWORD + 1)) + NumGet(addr + 32, "uint"), SizeFormat, SizeSuffix)
		FIND_DATA["FileName"]          := StrGet(addr + 44, "utf-16")
		FIND_DATA["AlternateFileName"] := StrGet(addr + 44 + MAX_PATH * (A_IsUnicode ? 2 : 1), "utf-16")
		return FIND_DATA
	}


	FileTime(FileTime, TimeFormat := "system")
	{
		addr := 0
		if (TimeFormat = "system")
			addr := this.FileTimeToSystemTime(FileTime)
		else if (TimeFormat = "local")
			addr := this.FileTimeToLocalFileTime(FileTime)
		else
			return false

		if (addr)
		{
			return Format("{:04}{:02}{:02}{:02}{:02}{:02}"
					, NumGet(addr,  0, "ushort")
					, NumGet(addr,  2, "ushort")
					, NumGet(addr,  6, "ushort")
					, NumGet(addr,  8, "ushort")
					, NumGet(addr, 10, "ushort")
					, NumGet(addr, 12, "ushort"))
		}
		return false
	}


	FileTimeToSystemTime(FileTime)
	{
		VarSetCapacity(SystemTime, 16, 0)
		if (DllCall("FileTimeToSystemTime", "ptr", &FileTime, "ptr", &SystemTime))
			return &SystemTime
		return false
	}


	FileTimeToLocalFileTime(FileTime)
	{
		VarSetCapacity(LocalTime, 16, 0)
		if (DllCall("FileTimeToLocalFileTime", "ptr", &FileTime, "ptr", &LocalTime))
			return &LocalTime
		return false
	}


	SystemTimeToTzSpecificLocalTime(SystemTime)
	{
		VarSetCapacity(LocalTime, 16, 0)
		if (DllCall("SystemTimeToTzSpecificLocalTime", "ptr", 0, "ptr", &SystemTime, "ptr", &LocalTime))
			return &LocalTime
		return false
	}


	FormatBytes(bytes, SizeFormat := "auto", suffix := false)
	{
		static SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT    := 0x0001
		static SFBS_FLAGS_TRUNCATE_UNDISPLAYED_DECIMAL_DIGITS := 0x0002
		static S_OK := 0

		if (SizeFormat = "auto")
		{
			size := VarSetCapacity(buf, 1024, 0)
			if (DllCall("shlwapi\StrFormatByteSizeEx", "int64", bytes, "int", SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT, "str", buf, "uint", size) = S_OK)
				output := buf
		}
		else if (SizeFormat = "kilobytes" || SizeFormat = "kb")
			output := Round(bytes / 1024, 2) . (suffix ? " KB" : "")
		else if (SizeFormat = "megabytes" || SizeFormat = "mb")
			output := Round(bytes / 1024**2, 2) . (suffix ? " MB" : "")
		else if (SizeFormat = "gigabytes" || SizeFormat = "gb")
			output := Round(bytes / 1024**3, 2) . (suffix ? " GB" : "")
		else if (SizeFormat = "terabytes" || SizeFormat = "tb")
			output := Round(bytes / 1024**4, 2) . (suffix ? " TB" : "")
		else
			output := Round(bytes, 2) . (suffix ? " Bytes" : "")
		return output
	}

...
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

swagfag
Posts: 4008
Joined: 11 Jan 2017, 17:59

Re: WIN32_FIND_DATA structure

Post by swagfag » 29 Jul 2020, 07:57

  • using the wrong pointer
  • UB: accessing out of scope local variables

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 29 Jul 2020, 09:31

First one is done and works.

But for the "FILETIME" I still get strange outputs. Even if its in the same function

Code: Select all

	FindFirstFile(hConnect, ByRef hFind, SearchFile := "*.*", TimeFormat := "system", SizeFormat := "auto", SizeSuffix := false)
	{
		VarSetCapacity(WIN32_FIND_DATA, (A_IsUnicode ? 592 : 320), 0)
		if (hFind := DllCall("wininet\FtpFindFirstFile", "ptr", hConnect, "str", SearchFile, "ptr", &WIN32_FIND_DATA, "uint", 0, "uint*", 0))
		{

			;MsgBox % FileTime := NumGet(&WIN32_FIND_DATA + 4, "uint")
			VarSetCapacity(FileTime, 8)
			DllCall("RtlMoveMemory", "str", FileTime, "uint", &WIN32_FIND_DATA + 4, "uint", 8)

			;VarSetCapacity(LocalTime, 16, 0)
			;DllCall("FileTimeToLocalFileTime", "ptr", &FileTime, "ptr", &LocalTime)

			VarSetCapacity(SystemTime, 16, 0)
			DllCall("FileTimeToSystemTime", "ptr", &FileTime, "ptr", &SystemTime)
			MsgBox % NumGet(SystemTime, 0, "ushort")
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

swagfag
Posts: 4008
Joined: 11 Jan 2017, 17:59

Re: WIN32_FIND_DATA structure

Post by swagfag » 29 Jul 2020, 10:03

Code: Select all

DllCall("RtlMoveMemory", "str", FileTime, "uint", &WIN32_FIND_DATA + 4, "uint", 8)
should be

Code: Select all

DllCall("RtlMoveMemory", "Ptr", &FileTime, "Ptr", &WIN32_FIND_DATA + 4, "Ptr", 8)

Code: Select all

;VarSetCapacity(LocalTime, 16, 0)
			;DllCall("FileTimeToLocalFileTime", "ptr", &FileTime, "ptr", &LocalTime)
LocalTime should be a FILETIME struct of size 8

thats as far as syntax goes. any other errors can only be attributed to other(unseen) syntax error or incorrect api usage. what does "strange outputs for FILETIME" mean?

Code: Select all

;MsgBox % FileTime := NumGet(&WIN32_FIND_DATA + 4, "uint")
returns the value of the DWORD dwLowDateTime member of the filetime struct, not a pointer to the struct or whatever

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 30 Jul 2020, 03:58

Selbst wenn ich mich an den im Forum bereits versuchten Klassen / Funktionen halte, bekomme ich trotzdem immer falsche werte zurück.
Even if I stick to the classes / functions already tried in the forum, I still always get wrong values back.

while FileSize works perfect

Code: Select all

FileSize := (NumGet(&WIN32_FIND_DATA + 28, "uint") * (MAXDWORD + 1)) + NumGet(&WIN32_FIND_DATA + 32, "uint")
MsgBox % FileSize    ; -> 6 (bytes)
i still stuck with FileTime. I tried every thing I found on this forum about WIN32_FIND_DATA

Code: Select all

;VarSetCapacity(FileTime, 8, 0)
;FileTime := NumGet(&WIN32_FIND_DATA + 4, "uint") << 32 | NumGet(&WIN32_FIND_DATA + 8, "uint")		; -> returns 1601
;FileTime := NumGet(&WIN32_FIND_DATA + 4, "ptr")													; -> returns 1601
;DllCall("RtlMoveMemory", "ptr", &FileTime, "ptr", &WIN32_FIND_DATA + 4, "uptr", 8)					; -> returns 1601
;DllCall("RtlMoveMemory", "ptr", FileTime, "ptr", &WIN32_FIND_DATA + 4, "uptr", 8)					; -> returns 1601

VarSetCapacity(SystemTime, 16, 0)
DllCall("FileTimeToSystemTime", "ptr", &FileTime, "ptr", &SystemTime)

MsgBox % NumGet(SystemTime, 0, "ushort")    ; -> should be 2020 (Year)
I don't know if I'm on the tube or just blind to see the error.
(sounds better in german: Keine Ahnung ob ich auf dem Schlauch stehe oder einfach nur Blind bin, den Fehler zu sehen.)
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 30 Jul 2020, 04:15

Uff.. I got it...

Code: Select all

VarSetCapacity(FileTime, 8, 0)
DllCall("RtlMoveMemory", "ptr", &FileTime, "ptr", &WIN32_FIND_DATA + 20, "uptr", 8)
VarSetCapacity(SystemTime, 16, 0)
DllCall("FileTimeToSystemTime", "ptr", &FileTime, "ptr", &SystemTime)
MsgBox % "Year: " NumGet(SystemTime, 0, "ushort")
My focus was too much on "CreationTime"... which still returns 1601. Also "LastAccessTime" returns 1601.
But "LastWriteTime" returns now 2020
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 30 Jul 2020, 07:51

[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

just me
Posts: 7287
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: WIN32_FIND_DATA structure

Post by just me » 30 Jul 2020, 10:03

Moin,

die Funktion FileTimeToSystemTime erwartet ja zwei Pointer:
1. einen Pointer auf eine FILETIME-Struktur,
2. einen Pointer auf eine SYSTEMTIME-Struktur.

Der Wert des Pointers auf die FILETIME-Struktur(ren) ist &WIN32_FIND_DATA + 4/12/20. Diesen Wert kannst Du der Funktion direkt übergeben. Das Auslesen und Zwischenspeichern des Inhalts brauchst Du dafür nicht.

Wenn Du den Wert in eine eigene Variable legen willst, sollte Folgendes funktionieren:

Code: Select all

VarSetCapacity(FileTime, 8, 0)
NumPut(NumGet(&WIN32_FIND_DATA + 20, "UInt64"), FileTime, "UInt64")
VarSetCapacity(SystemTime, 16, 0)
DllCall("FileTimeToSystemTime", "Ptr", &FileTime, "Ptr", &SystemTime)
; -------------------------------------------------------------------
; oder alternativ
; -------------------------------------------------------------------
FileTime := NumGet(&WIN32_FIND_DATA + 20, "UInt64")
VarSetCapacity(SystemTime, 16, 0)
DllCall("FileTimeToSystemTime", "Int64P", FileTime, "Ptr", &SystemTime)
(Der Speicherbereich einer FILETIME-Struktur ist wie der eines Int64-Werts aufgebaut.)

User avatar
jNizM
Posts: 2662
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
Contact:

Re: WIN32_FIND_DATA structure

Post by jNizM » 31 Jul 2020, 01:26

Danke euch beide. Habe es an der "alternative" angepasst.
[AHK] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you

just me
Posts: 7287
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: WIN32_FIND_DATA structure

Post by just me » 01 Aug 2020, 04:21

Moin,

Code: Select all

FileTime(addr)
{
   this.FileTimeToSystemTime(addr, SystemTime)
   ...
}
erweckt sehr stark den Anschein, dass in addr ein Pointer und kein Wert übergeben wird. Und genau so hatte ich mir das auch vorgestellt:

Code: Select all

FindData(ByRef WIN32_FIND_DATA, SizeFormat := "auto", SizeSuffix := false)
{
   ...
   FIND_DATA["CreationTime"]      := this.FileTime(addr +  4)
   FIND_DATA["LastAccessTime"]    := this.FileTime(addr + 12)
   FIND_DATA["LastWriteTime"]     := this.FileTime(addr + 20)
   ...
}
...
FileTime(addr)
{
   this.FileTimeToSystemTime(addr, SystemTime)
   this.SystemTimeToTzSpecificLocalTime(&SystemTime, LocalTime)
   ...
}
...
FileTimeToSystemTime(FileTimePtr, ByRef SystemTime)
{
   VarSetCapacity(SystemTime, 16, 0)
   if (DllCall("FileTimeToSystemTime", "ptr", FileTimePtr, "ptr", &SystemTime))
      return true
   return false
}
Für FtpFindFirstFile gibt es eine möglicherweise interessante Anmerkung:
Remarks

For FtpFindFirstFile, file times returned in the WIN32_FIND_DATA structure are in the local time zone, not in a coordinated universal time (UTC) format.

Post Reply

Return to “Ich brauche Hilfe”