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.