AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

Ein Thema von Sir Rufo · begonnen am 13. Aug 2015 · letzter Beitrag vom 13. Aug 2015
Antwort Antwort
Seite 1 von 2  1 2   
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 11:34
Warum wurde die Win32Api Funktion
Code:
BOOL WINAPI GetDiskFreeSpaceEx(
  _In_opt_  LPCTSTR        lpDirectoryName,
  _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable,
  _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes,
  _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes
);
in Delphi so deklariert
Delphi-Quellcode:
function GetDiskFreeSpaceEx(
  {} lpDirectoryName: LPCWSTR;
  // äh, wieso var und ohne Typen-Angabe?
  {} var
  {}   lpFreeBytesAvailableToCaller,
  {}   lpTotalNumberOfBytes;
  // ja, das verstehe ich wieder
  {} lpTotalNumberOfFreeBytes: PLargeInteger
  ): BOOL; stdcall;
und nicht so
Delphi-Quellcode:
function GetDiskFreeSpaceEx(
  {} lpDirectoryName: LPCWSTR;
  {} lpFreeBytesAvailableToCaller: PLargeInteger;
  {} lpTotalNumberOfBytes: PLargeInteger;
  {} lpTotalNumberOfFreeBytes: PLargeInteger
  ): BOOL; stdcall;
Warum werden zwei Parameter bewusst falsch implementiert und der letzte korrekt?

Folgender Aufruf (nach der Win32Api wäre das völlig korrekt) wird sofort angemeckert.
Delphi-Quellcode:
GetDisFreeSpaceEx(
  'C:\',
  nil, // <- Mecker
  nil, // <- Mecker
  nil );
Eine mögliche Antwort darauf könnte sein, dass diese Funktion in der RTL verwendet wird.
Delphi-Quellcode:
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;
So, weil dort also zwei Parameter immer gesetzt werden und der letzte Parameter nicht benötigt wird und somit auf nil gesetzt werden soll, hat man also den Api-Aufruf so deklariert, dass der zu dieser Funktion passt.

Gut man hätte die Api-Funktion auch richtig deklarieren können und diese Funktion so umsetzen:
Delphi-Quellcode:
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 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.

Ich mache mir die Welt, wie sie mir gefällt.

Ü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.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.109 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 11:42
Dass die Parameter als var x: TIrgendeinTyp statt const x: PIrgendeinTyp deklariert werden sehe ich in der WinApi ständig. Nervt mich auch, ich verstehe den Sinn dahinter nicht.

Anscheinend hatte man da mal eine Phase wo man den Benutzer (Programmierer) unter allen Umständen von Pointern fernhalten wollte.
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 11:51
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
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.330 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 11:53
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:
Delphi-Quellcode:
  GetDiskFreeSpaceEx: function (Directory: PChar; var FreeAvailable,
    TotalSpace: TLargeInteger; TotalFree: PLargeInteger): Bool stdcall = nil;
Dass man dort so nicht nil übergeben kann, ist sicher richtig. Aber das dürfte wohl in der Mehrheit der Fälle nicht wichtig sein...

// EDIT:
Ich sehe grad, dass es die Funktion zweimal gibt. Einmal in Winapi.Windows und einmal in System.SysUtils.
In der SysUtils sieht sie aus wie ich es gepostet habe...
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!

Geändert von jaenicke (13. Aug 2015 um 11:56 Uhr)
  Mit Zitat antworten Zitat
mensch72

Registriert seit: 6. Feb 2008
838 Beiträge
 
#5

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 11:53
"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.
  Mit Zitat antworten Zitat
Alt 13. Aug 2015, 11:56     Erstellt von redox
Dieser Beitrag wurde von Luckie gelöscht. - Grund: Zusammenhangsloses, wirres, offtipic Geschreibsel.
Benutzerbild von frankyboy1974
frankyboy1974

Registriert seit: 7. Apr 2015
Ort: SH
169 Beiträge
 
Delphi XE7 Professional
 
#6

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 12:13
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.

mfg

frank
Java ist auch eine Insel.
Ist Delphi von Oracle?
In meiner Buchstabensuppen fehlt das C++!
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#7

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 12:28
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?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Sunec

Registriert seit: 31. Aug 2013
88 Beiträge
 
Delphi XE8 Architect
 
#8

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 12:30
Es ist nicht nur die Winapi.Windows. Auch Funktionen der Winapi.D2D1 wurden absichtlich falsch implementiert.


Habe diesbezüglich auch hier einen Thread:

http://www.delphipraxis.net/185925-d...ml#post1311751
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.059 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 13:31
Es ist nicht nur die Winapi.Windows. Auch Funktionen der Winapi.D2D1 wurden absichtlich falsch implementiert.
Und dann kann man auch gleich mal anmeckern, dass gerade für Direct2D seit Delphi 2010 so gut wie nichts gemacht wurde und die ganzen Erweiterungen aus Direct2D 1.1, 1.2 und 1.3 (Windows 10) nicht mal ansatzweise übernommen wurden.

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.
  Mit Zitat antworten Zitat
Sunec

Registriert seit: 31. Aug 2013
88 Beiträge
 
Delphi XE8 Architect
 
#10

AW: Falsch/Inkonsistent definierte Win32Api Funktionen in Winapi.Windows

  Alt 13. Aug 2015, 14:04
Es ist nicht nur die Winapi.Windows. Auch Funktionen der Winapi.D2D1 wurden absichtlich falsch implementiert.
Und dann kann man auch gleich mal anmeckern, dass gerade für Direct2D seit Delphi 2010 so gut wie nichts gemacht wurde und die ganzen Erweiterungen aus Direct2D 1.1, 1.2 und 1.3 (Windows 10) nicht mal ansatzweise übernommen wurden.

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.
Das würde ja bedeuten, dass selbst die Übersetzung hier (http://www.delphipraxis.net/179042-h...t2d-1-1-a.html) aktueller ist als die in XE8.

Es ist wohl auch nicht davon auszugehen, dass XE9 Änderungen diesbezüglich bringt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz