Benutzer mit den meisten Antworten
Pfad Angaben unter Windows XP anders als unter Windows 7?

Frage
-
Hallo,
ich habe eine Applikation entwickelt, die mehrere externe Batch-Programme startet.
Die Programme, liegen in einem untergeordneten Ordner im Projektordner, in der auch die *.exe enthalten ist.
Also
starteApp.exe ist z.B. in C:\App enthalten
externeApp1 ist dann in C:\App\ext1 enthalten
Die externen Programme werden mit einer Process.Start Methode aufgerufen.
Process.Start = "ext1\\externeApp1.exe"
unter Windows 7 funktioniert das alles einwandfrei.
Leider nur unter Windows XP nicht. Dort wird eine FileNotFound Exception geworfen, also das er die externeApp1.exe nicht auffinden kann.
Hast Windows XP eine andere Zuodnung was Dateien angeht?
Bin Ratlos.....
Schöne Grüße
Marcel
OS: WIndows 7 Prof. 8x64) IDE: Visual Studio 2010 Ultimate, Expression Blend 4 Framework: dotNET 4
Antworten
-
Hallo Marcel,
ich denke mal, dass es an falschen oder anderen Pfaden auf dem XP-Rechner liegt, oder Du gehst unsichererweise von der CurrentDirectory aus, was nicht "best practice" ist. Du hast ja nun auch den Pfad relativ angegeben - das geht, aber dann möglichst mit WorkingDirectory. Dennoch würde ich die Pfade lieber in ihrer vollständigen Form benutzen.
Hier ein Beispiel:using System; using System.Diagnostics; using System.IO; using System.Reflection; namespace ConBatchDemo { class Program { static string externeApp = "ExterneApp1.exe"; static string subVerzeichnis = "Ext1"; static string Ausführungspfad; static void Main(string[] args) { Ausführungspfad = VerzeichnisPfad(Assembly.GetExecutingAssembly()); string programmPfad = GesamtPfad(subVerzeichnis, externeApp); StarteProgramm(programmPfad); } private static void StarteProgramm(string programmPfad) { ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = programmPfad; psi.Arguments = ""; psi.UseShellExecute = false; psi.WorkingDirectory = Path.GetDirectoryName(programmPfad); Process.Start(psi); } private static string VerzeichnisPfad(Assembly assembly) { string location = Path.GetDirectoryName(assembly.Location); if (!Directory.Exists(location)) FehlerInfoExistenz("Verzeichnis", location); return location; } private static string GesamtPfad(string verzeichnis, string programmDateiname) { if (!Directory.Exists(verzeichnis)) FehlerInfoExistenz("Verzeichnis", verzeichnis); string pfad = Path.Combine(verzeichnis, programmDateiname); if (!File.Exists(pfad)) FehlerInfoExistenz("Programmdatei", pfad); return pfad; } private static void FehlerInfoExistenz(string info, string pfad) { throw new Exception(info + " existiert nicht:\r\n\"" + pfad + "\""); } } }
In Deiner "ExterneApp1.exe" solltest Du ebenfalls unabhängig von der CurrentDirectory entwickeln.
Das ist in meinem Quellcode zum Beispiel mit:Ausführungspfad = VerzeichnisPfad(Assembly.GetExecutingAssembly());
gemacht, es gibt aber, je nach Applikationstyp auch andere Methoden, wie "Application.StartupPath" etc.
ciao Frank- Als Antwort vorgeschlagen Frank Dzaebel Donnerstag, 21. Juli 2011 09:46
- Als Antwort markiert Thorsten DörflerEditor Freitag, 22. Juli 2011 06:05
-
Hallo,
grundsätzlich sollte man relative Pfade bevorzugen, denn das vermindert den Anpassungsaufwand.
Für Dich evtl. schon deswegen relevant, weil Du unter X64 entwickelst, XP (bis auf Raritäten) als X86 (32-Bit) läuft.
Und sich System-Verzeichnis wie z. B. die Programm Verzeichnisse ändern können.
Hier ist aber weniger die Frage relativ Pfad oder nicht, sondern wo ist mein aktuelles Verzeichnis.
CreateProcess - was am Ende dahinter steht - sagt dazu:The string can specify the full path and file name of the module to execute or it can specify a partial name.
In the case of a partial name, the function uses the current drive and current directory to complete the specification.
The function will not use the search path. This parameter must include the file name extension; no default extension is assumed.Das derzeit aktuelle Verzeichnis erhältst Du in .NET über Directory.GetCurrentDirectory
und das ist nicht zwangsläufig das Verzeichnis der Anwendung, und es kann sich ändern -
z. B. durch SetCurrentDirectory - auch wenn das nicht die feine, weil unkooperative, Art ist.
(Environment.CurrentDirectory verwendet die obigen Methoden)Das WorkingDirectory entspricht dem lpCurrentDirectory Parameter von CreateProcess.
("primarily for shells" meint u. a. ShellExecute aka die Windows Shell)Zum Stackoverflow-Link:
Wie C# MVP Jon Skeet dort schreibt hilft GetFullPath dabei nicht wirklich weiter,
da es bei relativen Angaben ebenfalls auf das aktuelle Verzeichnis zurückgreift.Wenn Du eine Windows Forms Anwendung als Oberfläche verwendest, so ist der einfachste Weg Application.ExecuteablePath[1].
Das verwendet Assembly.GetExecutingAssembly, was für Konsolenanwendungen geeignet wäre,
siehe dazu: http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-inDas damit erhaltene Verzeichnis kannst zum einen der WorkingDirectory Eigenschaft zuweisen.
Womit auch sichergestellt ist, dass das aufgerufene Programm weitere Abhängigkeiten dort sucht
(sonst "erbt" es Dein aktuelles Arbeitsverzeichnis)Ebenso kannst Du Deinen relativen Pfad über Path.Combine vervollständigen.
und ggf. auch vorab via File.Exists prüfen, ob sich das Programm dort überhaupt befindet.Ich hoffe, der Rundumschlag hat alle Klarheiten beseitigt ;-)
Gruß Elmar
[1] Als Fallback für die Fälle, wenn die Einstiegsanwendung keine .NET Anwendung ist,
wird das Verzeichnis anhand GetModuleFileName ermittelt; ohne Interop geht das über
(da wir hier von einer C# .NET Anwendung sprechen, das nur der Vollständigkeit halber).var executablePath = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
- Als Antwort vorgeschlagen Stefan FalzModerator Donnerstag, 21. Juli 2011 09:30
- Als Antwort markiert t2b Freitag, 22. Juli 2011 05:59
Alle Antworten
-
Hallo Marcel,
anstelle des Dateinamens kannst Du auch ein ProcessStartInfo Objekt erstellen und damit den Prozess starten.
Im Objekt kannst Du dann die Eigenschaft WorkingDirectory auf den Basispfad deiner Anwendung setzen.
Das Problem wird wohl sein, dass ohne Angabe eines Pfads dann bspw. C:\Windows\System32\ als WorkingDirectory verwendet wird und deine andere Exe dort gesucht wird.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Stefan, die ProcessStartInfo Methode hatte genutzt.
Jetzt hatte ich auf deinen Hinweis hin die Eigenschaft WorkingDirectory implementiert und eine Messagebox darauf angewand, die mir den Pfad ausgibt.
Der Pfad der Anwednung ist "" (leerer string), so steht es auch in der MSDN. Das klappt auch alles. Unter Windows XP zeigt er mir die selbe MessageBox an,
Leider funktioniert es trotzdem nicht und er sagt, er konnte die Datei nicht finden.
Mich wundert es , das es unter Windows 7 (sogar auf mehreren Clients ausprobiert ) funktioniert, leider aber nicht auf Win XP clients (auch auf mehreren Clients ausprobiert).
OS: WIndows 7 Prof. 8x64) IDE: Visual Studio 2010 Ultimate, Expression Blend 4 Framework: dotNET 4 -
Hallo Marcel,
ich denke mal, dass es an falschen oder anderen Pfaden auf dem XP-Rechner liegt, oder Du gehst unsichererweise von der CurrentDirectory aus, was nicht "best practice" ist. Du hast ja nun auch den Pfad relativ angegeben - das geht, aber dann möglichst mit WorkingDirectory. Dennoch würde ich die Pfade lieber in ihrer vollständigen Form benutzen.
Hier ein Beispiel:using System; using System.Diagnostics; using System.IO; using System.Reflection; namespace ConBatchDemo { class Program { static string externeApp = "ExterneApp1.exe"; static string subVerzeichnis = "Ext1"; static string Ausführungspfad; static void Main(string[] args) { Ausführungspfad = VerzeichnisPfad(Assembly.GetExecutingAssembly()); string programmPfad = GesamtPfad(subVerzeichnis, externeApp); StarteProgramm(programmPfad); } private static void StarteProgramm(string programmPfad) { ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = programmPfad; psi.Arguments = ""; psi.UseShellExecute = false; psi.WorkingDirectory = Path.GetDirectoryName(programmPfad); Process.Start(psi); } private static string VerzeichnisPfad(Assembly assembly) { string location = Path.GetDirectoryName(assembly.Location); if (!Directory.Exists(location)) FehlerInfoExistenz("Verzeichnis", location); return location; } private static string GesamtPfad(string verzeichnis, string programmDateiname) { if (!Directory.Exists(verzeichnis)) FehlerInfoExistenz("Verzeichnis", verzeichnis); string pfad = Path.Combine(verzeichnis, programmDateiname); if (!File.Exists(pfad)) FehlerInfoExistenz("Programmdatei", pfad); return pfad; } private static void FehlerInfoExistenz(string info, string pfad) { throw new Exception(info + " existiert nicht:\r\n\"" + pfad + "\""); } } }
In Deiner "ExterneApp1.exe" solltest Du ebenfalls unabhängig von der CurrentDirectory entwickeln.
Das ist in meinem Quellcode zum Beispiel mit:Ausführungspfad = VerzeichnisPfad(Assembly.GetExecutingAssembly());
gemacht, es gibt aber, je nach Applikationstyp auch andere Methoden, wie "Application.StartupPath" etc.
ciao Frank- Als Antwort vorgeschlagen Frank Dzaebel Donnerstag, 21. Juli 2011 09:46
- Als Antwort markiert Thorsten DörflerEditor Freitag, 22. Juli 2011 06:05
-
Hi,
Jetzt hatte ich auf deinen Hinweis hin die Eigenschaft WorkingDirectory implementiert und eine Messagebox darauf angewand, die mir den Pfad ausgibt.
Der Pfad der Anwednung ist "" (leerer string), so steht es auch in der MSDN. Das klappt auch alles. Unter Windows XP zeigt er mir die selbe MessageBox an,
Leider funktioniert es trotzdem nicht und er sagt, er konnte die Datei nicht finden.
Du sollst ja auch nicht das WorkingDirectory abfragen, sondern die Eigenschaft auf den Pfad deiner Anwendung setzen.
<ProcessStartInfo>.WorkingDirectory = "<PfadZuDeinerAnwendung>"; // bspw. X:\Ordner\Natürlich sollte man den Pfad in der Produktivversion dynamisch ermitteln (siehe Franks Posting) aber für einen Test, ob es denn damit klappt, reicht auch ein hart zugewiesener Pfad.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Stefan,
tut mir leid, hatte ich vergessen zu erwähnen. Hatte habe zudem auch die EIegnschaft gesetzt und in einer Messagebox danach abgefragt.
Also wenn ich das richtig verstehe, lieber absolute statt relative Pfade?
dann müsste auch das funktionieren..
http://stackoverflow.com/questions/1399008/how-to-convert-relative-path-to-absolute-path-in-windows-application
OS: WIndows 7 Prof. 8x64) IDE: Visual Studio 2010 Ultimate, Expression Blend 4 Framework: dotNET 4 -
Hallo,
grundsätzlich sollte man relative Pfade bevorzugen, denn das vermindert den Anpassungsaufwand.
Für Dich evtl. schon deswegen relevant, weil Du unter X64 entwickelst, XP (bis auf Raritäten) als X86 (32-Bit) läuft.
Und sich System-Verzeichnis wie z. B. die Programm Verzeichnisse ändern können.
Hier ist aber weniger die Frage relativ Pfad oder nicht, sondern wo ist mein aktuelles Verzeichnis.
CreateProcess - was am Ende dahinter steht - sagt dazu:The string can specify the full path and file name of the module to execute or it can specify a partial name.
In the case of a partial name, the function uses the current drive and current directory to complete the specification.
The function will not use the search path. This parameter must include the file name extension; no default extension is assumed.Das derzeit aktuelle Verzeichnis erhältst Du in .NET über Directory.GetCurrentDirectory
und das ist nicht zwangsläufig das Verzeichnis der Anwendung, und es kann sich ändern -
z. B. durch SetCurrentDirectory - auch wenn das nicht die feine, weil unkooperative, Art ist.
(Environment.CurrentDirectory verwendet die obigen Methoden)Das WorkingDirectory entspricht dem lpCurrentDirectory Parameter von CreateProcess.
("primarily for shells" meint u. a. ShellExecute aka die Windows Shell)Zum Stackoverflow-Link:
Wie C# MVP Jon Skeet dort schreibt hilft GetFullPath dabei nicht wirklich weiter,
da es bei relativen Angaben ebenfalls auf das aktuelle Verzeichnis zurückgreift.Wenn Du eine Windows Forms Anwendung als Oberfläche verwendest, so ist der einfachste Weg Application.ExecuteablePath[1].
Das verwendet Assembly.GetExecutingAssembly, was für Konsolenanwendungen geeignet wäre,
siehe dazu: http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-inDas damit erhaltene Verzeichnis kannst zum einen der WorkingDirectory Eigenschaft zuweisen.
Womit auch sichergestellt ist, dass das aufgerufene Programm weitere Abhängigkeiten dort sucht
(sonst "erbt" es Dein aktuelles Arbeitsverzeichnis)Ebenso kannst Du Deinen relativen Pfad über Path.Combine vervollständigen.
und ggf. auch vorab via File.Exists prüfen, ob sich das Programm dort überhaupt befindet.Ich hoffe, der Rundumschlag hat alle Klarheiten beseitigt ;-)
Gruß Elmar
[1] Als Fallback für die Fälle, wenn die Einstiegsanwendung keine .NET Anwendung ist,
wird das Verzeichnis anhand GetModuleFileName ermittelt; ohne Interop geht das über
(da wir hier von einer C# .NET Anwendung sprechen, das nur der Vollständigkeit halber).var executablePath = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
- Als Antwort vorgeschlagen Stefan FalzModerator Donnerstag, 21. Juli 2011 09:30
- Als Antwort markiert t2b Freitag, 22. Juli 2011 05:59
-
Hallo Marcel,
- ... lieber absolute statt relative Pfade?
Ja, grundsätzlich benutze (intern) möglichst absolute volle Pfade wie in meinem Hinweis. Schaue dort herein. Dabei setzt Du sie aber soweit es sinnvoll ist, relativ zusammen, um von der Logik her den Vorteil des semantisch relativen Pfades zu nutzen.
Um meinen Hinweis aus dem ersten Posting zu wiederholen: Applikationen, die auf dem scheinbar aktuellen Verzeichnis (siehe mein Posting) basieren, sind nicht vorteilhaft (nicht best practice), weil es viele Situationen gibt, wann das aktuelle Verzeichnis intern gewechselt wird.
Aufrufe über Links, mit anderen Berechtigungen, Host-Prozesse etc. verändern ggf. das aktuelle Verzeichnis.Deswegen mache es in allen Applikationen so, wie in meinem [Quellcode-Beispiel].
Und GetFullPath ist hier eher irrelevant, denn Du kannst die Pfade besser sauberer mit Path.Combine mittels eines saubereren Location der GetExecutingAssembly wie in meinem Beispiel zusammensetzen. Bzgl. GetFullPath hat Jon Skeet, der zwar nicht offizieller C# MVP ist, aber MVP mit Privat-Status (und Erhalt des MVP-Awards) auch schon einiges gesagt.
ciao Frank -
Hallo Elmar, hallo Frank,
vielen Dank für eure Antworten, die mir sehr weiter geholfen haben.
Ich frage jetzt per Path.GetDirectoryName(Assembly.GetExecutíngAssembly().Location) den absoluten Pfad zur Laufzeit ab.
Daran knüpfe ich die relativen Pfade der externen Anwendungen.
Und siehe da....es funktioniert!
vielen Dank
schöne Grüße
Marcel
OS: WIndows 7 Prof. 8x64) IDE: Visual Studio 2010 Ultimate, Expression Blend 4 Framework: dotNET 4