![]() |
Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Warum wurde die Win32Api Funktion
Code:
in Delphi so deklariert
BOOL WINAPI GetDiskFreeSpaceEx(
_In_opt_ LPCTSTR lpDirectoryName, _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable, _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes, _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes );
Delphi-Quellcode:
und nicht so
function GetDiskFreeSpaceEx(
{} lpDirectoryName: LPCWSTR; // äh, wieso var und ohne Typen-Angabe? {} var {} lpFreeBytesAvailableToCaller, {} lpTotalNumberOfBytes; // ja, das verstehe ich wieder {} lpTotalNumberOfFreeBytes: PLargeInteger ): BOOL; stdcall;
Delphi-Quellcode:
Warum werden zwei Parameter bewusst falsch implementiert und der letzte korrekt?
function GetDiskFreeSpaceEx(
{} lpDirectoryName: LPCWSTR; {} lpFreeBytesAvailableToCaller: PLargeInteger; {} lpTotalNumberOfBytes: PLargeInteger; {} lpTotalNumberOfFreeBytes: PLargeInteger ): BOOL; stdcall; Folgender Aufruf (nach der Win32Api wäre das völlig korrekt) wird sofort angemeckert.
Delphi-Quellcode:
Eine mögliche Antwort darauf könnte sein, dass diese Funktion in der RTL verwendet wird.
GetDisFreeSpaceEx(
'C:\', nil, // <- Mecker nil, // <- Mecker nil );
Delphi-Quellcode:
So, weil dort also zwei Parameter immer gesetzt werden und der letzte Parameter nicht benötigt wird und somit auf
unit System.SysUtils;
function InternalGetDiskSpace(Drive: Byte; var TotalSpace, FreeSpaceAvailable: Int64): Bool; var RootPath: array[0..4] of Char; RootPtr: PChar; begin RootPtr := nil; if Drive > 0 then begin RootPath[0] := Char(Drive + $40); RootPath[1] := ':'; RootPath[2] := '\'; RootPath[3] := #0; RootPtr := RootPath; end; Result := GetDiskFreeSpaceEx(RootPtr, FreeSpaceAvailable, TotalSpace, nil); end;
Delphi-Quellcode:
gesetzt werden soll, hat man also den Api-Aufruf so deklariert, dass der zu dieser Funktion passt.
nil
Gut man hätte die Api-Funktion auch richtig deklarieren können und diese Funktion so umsetzen:
Delphi-Quellcode:
Ich finde es jetzt auf die Schnelle nicht, aber solche fehlerhaften Übersetzungen der Api wurden/werden regelmässig als Bug gemeldet und mit der gleichen stoischen Regelmässigkeit als as designed geschlossen. Ja, nee .. is klar.
function InternalGetDiskSpace( Drive: Byte; var TotalSpace, FreeSpaceAvailable: Int64 ): Bool;
var RootPath: array [ 0 .. 4 ] of Char; RootPtr: PChar; begin RootPtr := nil; if Drive > 0 then begin RootPath[ 0 ] := Char( Drive + $40 ); RootPath[ 1 ] := ':'; RootPath[ 2 ] := '\'; RootPath[ 3 ] := #0; RootPtr := RootPath; end; Result := GetDiskFreeSpaceEx( RootPtr, PLargeInteger( FreeSpaceAvailable ), PLargeInteger( TotalSpace ), nil ); end; Ich mache mir die Welt, wie sie mir gefällt. :shock: Übrig bleibt dann nur noch, sich diese Funktionen selber zu deklarieren - gut dann aber auch so richtig richtig:
Delphi-Quellcode:
unit netAlike.Winapi.Windows;
interface uses Winapi.Windows; procedure CheckApiCall( ApiCallResult: BOOL; const AdditionalInfo: string = '' ); {$REGION 'GetDiskFreeSpaceEx'} /// <summary> /// Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, /// the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread. /// </summary> /// <param name="lpDirectoryName">[in, optional] /// <para>A directory on the disk.</para> /// <para>If this parameter is NULL, the function uses the root of the current disk.</para> /// <para>If this parameter is a UNC name, it must include a trailing backslash, for example, "\\MyServer\MyShare\".</para> /// <para>This parameter does not have to specify the root directory on a disk. The function accepts any directory on a disk.</para> /// <para>The calling application must have <see cref="FILE_LIST_DIRECTORY"/> access rights for this directory.</para> /// </param> /// <param name="lpFreeBytesAvailableToCaller">[out, optional] /// <para> /// A pointer to a variable that receives the total number of free bytes on a disk that are available /// to the user who is associated with the calling thread. /// </para> /// <para>This parameter can be NULL.</para> /// <para>If per-user quotas are being used, this value may be less than the total number of free bytes on a disk.</para> /// </param> /// <param name="lpTotalNumberOfBytes">[out, optional] /// <para> /// A pointer to a variable that receives the total number of bytes on a disk that are available to the user /// who is associated with the calling thread. /// </para> /// <para>This parameter can be NULL.</para> /// <para>If per-user quotas are being used, this value may be less than the total number of bytes on a disk.</para> /// <para>To determine the total number of bytes on a disk or volume, use <see cref="IOCTL_DISK_GET_LENGTH_INFO"/>.</para> /// </param> /// <param name="lpTotalNumberOfFreeBytes">[out, optional] /// <para>A pointer to a variable that receives the total number of free bytes on a disk.</para> /// <para>This parameter can be NULL.</para> /// </param> function GetDiskFreeSpaceEx( { IN OPT } lpDirectoryName: LPCWSTR; { OUT OPT } lpFreeBytesAvailableToCaller: PLargeInteger; { OUT OPT } lpTotalNumberOfBytes: PLargeInteger; { OUT OPT } lpTotalNumberOfFreeBytes: PLargeInteger ): BOOL; stdcall; {$EXTERNALSYM GetDiskFreeSpaceEx} function GetDiskFreeSpaceExA( { IN OPT } lpDirectoryName: LPCSTR; { OUT OPT } lpFreeBytesAvailableToCaller: PLargeInteger; { OUT OPT } lpTotalNumberOfBytes: PLargeInteger; { OUT OPT } lpTotalNumberOfFreeBytes: PLargeInteger ): BOOL; stdcall; {$EXTERNALSYM GetDiskFreeSpaceExA} function GetDiskFreeSpaceExW( { IN OPT } lpDirectoryName: LPCWSTR; { OUT OPT } lpFreeBytesAvailableToCaller: PLargeInteger; { OUT OPT } lpTotalNumberOfBytes: PLargeInteger; { OUT OPT } lpTotalNumberOfFreeBytes: PLargeInteger ): BOOL; stdcall; {$ENDREGION} {$REGION 'GetVolumeInformation'} /// <summary> /// Retrieves information about the file system and volume associated with the specified root directory. /// </summary> /// <param name="lpRootPathName">[in, optional] /// <para>A pointer to a string that contains the root directory of the volume to be described.</para> /// <para> /// If this parameter is NULL, the root of the current directory is used. A trailing backslash is required. /// For example, you specify \\MyServer\MyShare as "\\MyServer\MyShare\", or the C drive as "C:\". /// </para> /// </param> /// <param name="lpVolumeNameBuffer">[out, optional] /// <para> /// A pointer to a buffer that receives the name of a specified volume. The buffer size is specified by /// the nVolumeNameSize parameter. /// </para> /// </param> /// <param name="nVolumeNameSize">[in] /// <para>The length of a volume name buffer, in TCHARs. The maximum buffer size is MAX_PATH+1.</para> /// <para>This parameter is ignored if the volume name buffer is not supplied.</para> /// </param> /// <param name="lpVolumeSerialNumber">[out, optional] /// <para>A pointer to a variable that receives the volume serial number.</para> /// <para>This parameter can be NULL if the serial number is not required.</para> /// <para> /// This function returns the volume serial number that the operating system assigns when a hard disk is formatted. /// To programmatically obtain the hard disk's serial number that the manufacturer assigns, use the Windows Management /// Instrumentation (WMI) Win32_PhysicalMedia property SerialNumber. /// </para> /// </param> /// <param name="lpMaximumComponentLength">[out, optional] /// <para>A pointer to a variable that receives the maximum length, in TCHARs, of a file name component that a specified file system supports.</para> /// <para>A file name component is the portion of a file name between backslashes.</para> /// <para> /// The value that is stored in the variable that *lpMaximumComponentLength points to is used to indicate that a /// specified file system supports long names. For example, for a FAT file system that supports long names, the /// function stores the value 255, rather than the previous 8.3 indicator. Long names can also be supported on /// systems that use the NTFS file system. /// </para> /// </param> /// <param name="lpFileSystemFlags">[out, optional] /// <para>A pointer to a variable that receives flags associated with the specified file system.</para> /// <para>This parameter can be one or more of the following flags. However, FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED are mutually exclusive.</para> /// </param> /// <param name="lpFileSystemNameBuffer">[out, optional] /// <para> /// A pointer to a buffer that receives the name of the file system, for example, the FAT file system or the NTFS file system. /// The buffer size is specified by the nFileSystemNameSize parameter. /// </para> /// </param> /// <param name="nFileSystemNameSize">[in] /// <para>The length of the file system name buffer, in TCHARs. The maximum buffer size is MAX_PATH+1.</para> /// <para>This parameter is ignored if the file system name buffer is not supplied.</para> /// </param> function GetVolumeInformation( { IN OPT } lpRootPathName: LPCWSTR; { OUT OPT } lpVolumeNameBuffer: LPWSTR; { IN } nVolumeNameSize: DWORD; { OUT OPT } lpVolumeSerialNumber: LPDWORD; { OUT OPT } lpMaximumComponentLength: LPDWORD; { OUT OPT } lpFileSystemFlags: LPDWORD; { OUT OPT } lpFileSystemNameBuffer: LPWSTR; { IN } nFileSystemNameSize: DWORD ): BOOL; stdcall; {$EXTERNALSYM GetVolumeInformation} function GetVolumeInformationA( { IN OPT } lpRootPathName: LPCSTR; { OUT OPT } lpVolumeNameBuffer: LPSTR; { IN } nVolumeNameSize: DWORD; { OUT OPT } lpVolumeSerialNumber: LPDWORD; { OUT OPT } lpMaximumComponentLength: LPDWORD; { OUT OPT } lpFileSystemFlags: LPDWORD; { OUT OPT } lpFileSystemNameBuffer: LPSTR; { IN } nFileSystemNameSize: DWORD ): BOOL; stdcall; {$EXTERNALSYM GetVolumeInformationA} function GetVolumeInformationW( { IN OPT } lpRootPathName: LPCWSTR; { OUT OPT } lpVolumeNameBuffer: LPWSTR; { IN } nVolumeNameSize: DWORD; { OUT OPT } lpVolumeSerialNumber: LPDWORD; { OUT OPT } lpMaximumComponentLength: LPDWORD; { OUT OPT } lpFileSystemFlags: LPDWORD; { OUT OPT } lpFileSystemNameBuffer: LPWSTR; { IN } nFileSystemNameSize: DWORD ): BOOL; stdcall; {$EXTERNALSYM GetVolumeInformationW} {$ENDREGION} implementation uses System.SysUtils; procedure CheckApiCall( ApiCallResult: BOOL; const AdditionalInfo: string ); begin if not ApiCallResult then RaiseLastOsError( GetLastError, sLineBreak + AdditionalInfo ); end; function GetDiskFreeSpaceEx; external kernelbase name 'GetDiskFreeSpaceExW'; function GetDiskFreeSpaceExA; external kernelbase name 'GetDiskFreeSpaceExA'; function GetDiskFreeSpaceExW; external kernelbase name 'GetDiskFreeSpaceExW'; function GetVolumeInformation; external kernelbase name 'GetVolumeInformationW'; function GetVolumeInformationA; external kernelbase name 'GetVolumeInformationA'; function GetVolumeInformationW; external kernelbase name 'GetVolumeInformationW'; end. |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Dass die Parameter als
Delphi-Quellcode:
statt
var x: TIrgendeinTyp
Delphi-Quellcode:
deklariert werden sehe ich in der WinApi ständig. Nervt mich auch, ich verstehe den Sinn dahinter nicht.
const x: PIrgendeinTyp
Anscheinend hatte man da mal eine Phase wo man den Benutzer (Programmierer) unter allen Umständen von Pointern fernhalten wollte. |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Es ist schön, daß Du Dich darum gekümmert hast, und das scheint mir so lehrreich, daß man damit etwas Zeit am WE verbringen kann.
Was aber wird die Reaktion des Benutzers/Programmierers sein der möglichst schnell funktionierenden Code produzieren soll? A) Die spinnen die Borländer B) Und für diesen **** soll ich auch noch Geld bezahlen zwischen diesen beiden Polen wird die Reaktion wohl angesiedelt sein. Die Möglichkeit, "das schau ich mir an, da stimmt doch was nicht" wird wohl nur von Enthusiasten in Erwägung gezogen. Gruß K-H |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Daraus var-Parameter zu machen finde ich schon sehr angenehm, allerdings finde ich es nicht gut, diese ohne Typ zu deklarieren...
In XE8 sieht die Deklaration aber korrekt aus: Zitat:
// EDIT: Ich sehe grad, dass es die Funktion zweimal gibt. Einmal in Winapi.Windows und einmal in System.SysUtils. :shock: In der SysUtils sieht sie aus wie ich es gepostet habe... |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
"var x: TIrgendeinTyp" nervt nicht nur, es verhindert auch das man da gezielt mal "nil" übergeben kann...
-> NIL/NULL als Parameter ist bei vielen WinApi Funktionen für Pointer erlaubt und hat da funktionsabhängig auch durchaus sinnvolle Bedeutungen und Sonderfunktionsfälle, welche einem per "var" in Delphi versperrt werden. |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Hallo,
vielleicht gibt es bei Emba mehr als einen Entwickler, der nun einen Kompromiss finden musste, zwischen Windows-Api und Delphi-Programmierung. In der Theorie sind die Dinge oft einfach, in der Praxis dagegen nicht so sehr. Ich kann mich daran erinnern, auch schon öfter die C-Nomenklatur nach Delphi zu übertragen, am Ende muss es funktionieren, aber nicht unbedingt schön sein. Auch bei Emba sitzen Menschen die sich aufs Wochenende freuen.:oops: mfg frank |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Na ja, die WinAPi ist ja schon selber nicht konsistent. Man gucke such nur mal GetUserName und GetComputerName an mit den vertauschten Parameter. Liegt aber daran, dass die Fzunktionen von unterschiedlichen Abteilungen implementiert wurden. Die eine wohl von der Kernel Abteilung und die andere von einer anderen Abteilung.
Was ich aber sagen will, wie willst was konsistent bekommen, was as designed schon inkonsistent ist? :wink: |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Es ist nicht nur die Winapi.Windows. Auch Funktionen der Winapi.D2D1 wurden absichtlich falsch implementiert.
Habe diesbezüglich auch hier einen Thread: ![]() |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Zitat:
Aber wo soll der Thread hinführen? Das nicht alles rund ist, lernt man ja spätestens nach drei Monaten mit der Sprache und Framework. |
AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows
Zitat:
![]() Es ist wohl auch nicht davon auszugehen, dass XE9 Änderungen diesbezüglich bringt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz