Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#8

AW: FindFirstFileNameW aufrufen

  Alt 12. Jan 2014, 00:13
Da ich schon mal dabei war, habe ich für CloseFile auch gleich die entsprechende Funktion aus kernel32.dll aufgerufen, da es ja in Delphi für FindFirstFileNameW nichts gibt.
Weil das kein "eigenes" FileClose hat?

Also warum nicht gleich das FileClose aus der Unit Windows nehmen, was Delphi schon bereitstellt?

Eine Sache ist merkwürdig und ärgerlich: Mit Verlassen der Routine '"ZeigeHardlinks" kommt es zu einer Zugriffsverletzung im Modul "oleaut32.dll" (Lesen). Hat da jemand eine Idee zu?
Was hab ich gesagt?
DU mußt den Speicher reservieren, wo der Dateiname reingeschrieben werden soll.

Es steht auch alles ganz genau in der Definition drin.
Zitat:
StringLength [in, out]

The size of the buffer pointed to by the LinkName parameter, in characters. If this call fails and the error returned from the GetLastError function is ERROR_MORE_DATA (234), the value that is returned by this parameter is the size that the buffer pointed to by LinkName must be to contain all the data.
LinkName [in, out]

A pointer to a buffer to store the first link name found for lpFileName.
Du hast weder den "Buffer" reserviert, noch die Größe des Buffers übergeben.

Zitat:
Showmessage(WideCharToString(@PLinkName));
Das ist so richtig?
Ein Zeiger auf den Zeiger ... ich kann mich täuschen, aber ich glaub nicht.

Daß es bei dir "funktionierte, liegt daran, daß du einen Zeiger auf die Variable "@LinkName" und nicht auf den Inhalt "@LinkName[1]" aka "PWideChar(LinkName)" übergeben hast.
In diesen Zeiger passen nur 4 Byte und da braucht man sich nicht wundern, wenn dahinter alles überschrieben wird.

Da war es auch egal, daß du noch keinen Speicher reserviert hattest, da der eh nicht genutzt wurde, aber hier hätte dir die Zugriffsverletzung bei Adresse 0 zu Denken gegeben, wenn du das richtig übergeben hättest.

Delphi-Quellcode:
procedure TForm1.ZeigeHardlinks;
var
  Dateiname : WideString;
  LinkLänge : Cardinal;
  LinkName : WideChar;
  PLinkName : PWideChar;
  Handle : Cardinal;
begin
  Dateiname := 'C:\Temp\Hardlink.JPG';
  SetLength(LinkName, MAX_PATH);
  LinkLänge := Length(LinkName);
  Handle := FindFirstFileNameW(PWideChar(Dateiname), 0, @LinkLänge, PWideChar(LinkName));
  If Handle = INVALID_HANDLE_VALUE // ja, so Einiges kennt Delphi auch schon
    then Showmessage(SysErrorMessage(GetLastError));
  Showmessage(PWideChar(LinkName)); // PChar->String kann Delphi automatisch umwandeln, aber wenn man vorher LinkName auf die "richtige" Länge setzt (bis vor die erste/abschließende #0, dann kann man diese String-Variable auch direkt verwenden)
  LinkLänge := Length(LinkName);
  While FindNextFileNameW(Handle, @LinkLänge, PWideChar(LinkName)) do
  begin
    Showmessage(WideChar(LinkName));
    LinkLänge := Length(LinkName);
  end;
  CloseFile(Handle);
end;


procedure TForm1.ZeigeHardlinks;
var
  Dateiname : WideString;
  LinkLänge : Cardinal;
  PLinkName : PWideChar;
  Handle : Cardinal;
begin
  Dateiname := 'C:\Temp\Hardlink.JPG';
  PLinkName := GetMemory(MAX_PATH * 2 + 2); // +2 für die abschließende #0
  LinkLänge := MAX_PATH;
  Handle := FindFirstFileNameW(PWideChar(Dateiname), 0, @LinkLänge, PLinkName);
  If Handle = INVALID_HANDLE_VALUE
    then Showmessage(SysErrorMessage(GetLastError)); // wieso wird hier eigentlich, auch bei einem Fehler, der nachfolgende Code dennoch ausgeührt?
  Showmessage(PLinkName);
  LinkLänge := MAX_PATH;
  While FindNextFileNameW(Handle, @LinkLänge, PLinkName) do
  begin
    Showmessage(PLinkName);
    LinkLänge := MAX_PATH;
  end;
  FreeMemory(PLinkName);
  CloseFile(Handle);
end;


procedure TForm1.ZeigeHardlinks;
var
  Dateiname : WideString;
  LinkLänge : Cardinal;
  LinkName : array[0..MAX_PATH] of WideChar;
  Handle : Cardinal;
begin
  Dateiname := 'C:\Temp\Hardlink.JPG';
  LinkLänge := MAX_PATH;
  Handle := FindFirstFileNameW(PWideChar(Dateiname), 0, @LinkLänge, @LinkName);
  If Handle = INVALID_HANDLE_VALUE then
    RaiseLastOSError;
  repeat
    ShowMessage(PWideChar(@LinkName));
    LinkLänge := MAX_PATH;
  until not FindNextFileNameW(Handle, @LinkLänge, @LinkName);
  CloseFile(Handle);
end;
Die fehlenden Resourcenschutzblöcke ignorier ich mal.
Und da deine Fehlerbehandlung nicht die Beste ist und der nachfolgende Code sowieso ausgeführt wird, wird das FreeMemory dennoch aufgerufen.
Außer es knallt was ganz schlimmes, wie z.B. bei deinem originalen Code, wo du dir einen netten BufferOverrun gebastelt hattest, aber da ist eh alles zu spät und das kleine Speicherleck stört dann auch nicht mehr.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (12. Jan 2014 um 00:18 Uhr)
  Mit Zitat antworten Zitat