GetCurrentDirectory liefert nicht den Pfad der Anwendung


... zumindest nicht zwingend.

Immer wenn in diversen Foren da nach gefragt wird, wie man denn den Pfad seiner Anwendung ermitteln könnne, wir sehr oft und leider genauso falsch mit GetCurrentDirectory geantwortet. Und irgendwie ist diese falsche Antwort nicht tot zu bekommen. Was wohl auch daran liegt, dass einfach nicht richtig getestet wird und es eben zufällig funktioniert.

Was gibt GetCurrentDirectory für einen Wert zurück? Laut PSDK:

The GetCurrentDirectory function retrieves the current directory for the current process.

Oder zu Deutsch: "Das aktuelle Verzeichnis für den Prozess". Und das ist der Fehler: Das aktuelle Verzeichnis muss eben nicht zwingend das Verzeichnis sein, in dem sich die Exe-Datei der Anwendung befindet. Direkt nach dem Start mag das ja noch stimmen, aber so bald man einmal eine Datei mit einem "Dateiöffnen"-Dialog geöffnet hat oder mit einem "Speichern unter"-Dialog gespeichert hat und dabei das Verzeichnis gewechselt hat, stimmt das schon nicht mehr. Wer es nicht glaubt, möge es ausprobieren:

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(GetCurrentDir);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Edit1.Text := OpenDialog1.FileName;
end;

Dies ist Delphi-Code, sollte aber kein Problem darstellen. Klickt man auf die Schaltfläche Eins (Button1) wird einfach ein Dialog angezeigt, der das aktuelle Verzeichnis ausgibt. GetCurrentDir ist der Delphi Wrapper für die API-Funktion GetCurrentDirectory. Schaltfläche Zwei (Button2) öffnet einen normalen "Dateiöffnen"-Dialog und zeigt den Pfad und die ausgewählte Datei in dem Textfeld Edit1 an.

Klickt man gleich nach dem Start auf Schaltfläche Eins, bekommt man als aktuelles Verzeichnis zum Beispiel so etwas:

E:\Delphi\Sourcecodes\In_Bearbeitung

Dies ist auch das Verzeichnis der Exe-Datei der Anwendung.

Öffnet man jetzt aber eine Datei mit der zweiten Schaltfläche und wechselt dabei das Verzeichnis, zum Beispiel wenn man die boot.ini im Wurzelverzeichnis von Laufwerk C: auswählt, dann bekommt man dies

C:\

als aktuelles Verzeichnis. Der "Dateiöffnen"-Dialog setzt bzw. ändert also das aktuelle Verzeichnis.

Will man jetzt also eine Ini-Datei lesen oder schreiben und man benutzt GetCurrentDirectory, dann kann das ganz schnell ins Auge gehen. Beim Schreiben merkt man es eventuell noch nicht mal, wenn man Schreibrechte in dem entsprechenden Ordner hat. Aber beim Lesen könnte es dann knallen, wenn die Datei nicht gefunden wird.

Gleiches gilt, wenn man bei einer Verknüpfung das Arbeitsverzeichnis ändert. Auch dann ist das aktuelle Verzeichnis nicht mehr das Verzeichnis in dem die Anwendung sich befindet.

Wie macht man es aber nun richtig? In dem man die richtige API-Funktion dafür verwendet und die wäre GetModuleFileName:

The GetModuleFileName function retrieves the fully-qualified path for the file that contains the specified module that the current process owns.
DWORD GetModuleFileName(
  HMODULE hModule,
  LPTSTR lpFilename,
  DWORD nSize
);

Übergibt man als ersten Parameter null, dann erhält man den Pfad und Exe-Namen des aufrufenden Prozesses:

function GetExePath(var ExePath: string): Boolean;
var
  Buffer            : array[0..MAX_PATH + 1] of Char;
  len               : Integer;
begin
  len := GetModuleFileName(0, Buffer, sizeof(Buffer));
  SetString(ExePath, Buffer, len);
  result := len <> 0;
end;

Und Delphi wäre nicht Delphi, wenn es da nicht schon was fertiges gäbe. Unter Delphi kann man einfach die Funktion ParamStr mit dem Index null aufrufen und erhält so den Pfad und den Namen der Exe-Datei:

procedure TForm1.Button4Click(Sender: TObject);
begin
  ShowMessage(ParamStr(0));
end;

Also noch mal: Wenn man den Pfad zu seiner Anwendung braucht, dann sollte man auf keinen Fall GetCurrentDirectory nehmen, sondern GetModuleFileName bzw. den entsprechenden Wrapper aus der verwendeten Bibliothek.


2010-12-29T23:44:46 +0100, mail+homepage[at]michael-puff.de