Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi in KommandozeilenAnwendung DOS-Befehl ausführen (https://www.delphipraxis.net/96447-kommandozeilenanwendung-dos-befehl-ausfuehren.html)

Tyler 24. Jul 2007 21:30


in KommandozeilenAnwendung DOS-Befehl ausführen
 
Hallo,

hab schon n paar Seiten durchwühlt, aber noch keine Antwort gefunden. Ich will den Parameter, den meine Konsolenanwendung erhält, per Dos-Befehl "SET" in den Umgebungsvariablen speichern. Weiss aber nicht ansastzweise, wie ich vorgehen soll.

Habt ihr ne Idee?

Danke,

tyler :)

Hawkeye219 24. Jul 2007 21:50

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Hallo Tyler,

hast du diesen Thread schon gelesen?

Gruß Hawkeye

Christian Seehase 24. Jul 2007 22:10

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Moin Tyler,

Dir muss dabei aber klar sein, dass Set nur im Kontext des aufrufenden Prozesses wirkt, dass heisst: Wird der Prozess (also Dein Konsolenprogramm) beendet, ist die Änderung weg. Das passiert, da beim Starten eines Programmes der neue Prozess ein Kopie des Environments des Aufrufers (in diesem Falle also der Konsole) bekommt. Es funktioniert nicht einmal, die Werte direkt in die Registry zu schreiben.

Einen groben Ansatz kann ich Dir geben (noch nicht ganz ausgereift, da er von einer festen Adresse bezüglich des Environmentblocks ausgeht, ausserdem darf das Environment nicht um soviel grösser werden, dass der Block neu zugewiesen werden muss, da sich sonst dessen Startadresse ändert.)

Diese Vorgehensweise geht davon aus, dass das Environment bei jeden Prozess immer an der gleichen Adresse beginnt, was, zumindest bis incl. XP, der Fall zu sein scheint.

Ermittle die Adresse Deines Environment-Blocks (geht sehr gut GetEnvironmentStringsW. Es muss die Widestring-Version sein, mit der Ascii-Version funktioniert es nicht).
Füge den neuen Environmentstring hinzu (SetEnvironmentVariableW).
Vergleiche die ermittelte Adresse mit der aktuellen. Stimmen die nicht überein: Schade, der Block wurde zu gross, und an eine neue Adresse verschoben, dass ist hier (nocht) nicht abgedeckt. Ansonsten kann es weiter gehen:

Ermittle den Parentprozess zu Deinem (CreateToolHelp32Snapshot).
Öffne diesen mit Schreibrechten (OpenProcess)
Ermittle mit VirtualQueryEx die MEMORY_BASIC_INFORMATION für den Environmenblock des Aufrufers.
Ändere mit VirtualProtectEx die Zugriffsrechte auf PAGE_READWRITE.
Kopiere Deinen Environmentblock in den des Aufrufers (WriteProcessMemory, Länge MEMORY_BASIC_INFORMATION.RegionSize)
Setze die Zugriffsrechte wieder zurück auf den Ursprungswert (VirtualProtectEx)
Jetzt noch alle Handle schliessen und fertig.

BTW:
Das ist nicht als Witz gemeint, unter 2000 und XP konnte ich das schon so machen (unter 2000 habe ich es auch schon mit Userrechten ausprobiert ;-))

Einen Beispielcode könnte ich aber frühestens am Wochenende fertig bekommen.


Falls Dir das zu aufwändig ist:
Microsoft schlägt für die Lösung dieses Problems vor, dass man aus seinem Konsolenprogramm heraus eine Batchdatei mit dem entsprechenden Set-Kommando erstellt, die dann nach dem Konsolenprogramm per Call aufgerufen wird.


(Das ist übrigens genau das Problem, dass mich zu einem Forum gebracht hat :mrgreen:)

Hawkeye219 24. Jul 2007 22:32

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Moin Chris,

in dem von mir verlinkten Thread verweist MathiasSimmack auf einen Beitrag im DF. Ich habe den dortigen Code zwar nicht getestet, aber er verspricht eine systemweite Änderung der Umgebungsvariablen.

Gruß Hawkeye

Christian Seehase 24. Jul 2007 22:55

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Moin Hawkeye,

ich habe es gerade einmal getestet.
Eine neue Anwendung, im OnCreate des Formuales dann die Variable setzen.
Wie erwartet: Anschliessend stand die Variable in der Konsole nicht zur Verfügung.
Der Broadcast hilft einem da nicht, da er von der Konsole nicht verarbeitet wird.
Macht man eine neuen Konsole auf ist der Wert dann da, was einem, im Zuge einer Batchverarbeitung aber leider nicht weiterhilft.

Hansa 25. Jul 2007 00:02

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
@Fragesteller : Erkläre mal bitte, warum eine Umgebungsvariable gesetzt werden MUSS. Geht das nicht anders, z.B. INI ? In einer Multitasking-Umgebung macht das SET tatsächlich wenig Sinn. Siehe Christians Vorlesung. :mrgreen:

Tyler 25. Jul 2007 07:07

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Zitat:

Zitat von Hawkeye219
Hallo Tyler,

hast du diesen Thread schon gelesen?

Gruß Hawkeye

tatsächlich... gabs das Problem schonmal. Aber den Thread hatte ich nicht gefunden, vielleicht weil ich nie nach "umgebungs variabeln" gesucht habe. Ich hab aber nach "EnvironmentVariable" gesucht.. seltsam. Egal, danke für den Link :)

@Christian
Vielen Dank, war mir bisher neu, dass Env-Variablen nur für eine CMD-Sitzung zählen. Allerdings würde mir das für den Anfang vielleicht schon reichen... denn:

@hansa
ich hatte gestern abend noch die fixe Idee, folgenden eigentlich einfachen Programmwunsch zu erfüllen

aus dem efb
Zitat:

Ausserdem eine Batch-Datei-Level-Lösung um (LFN) D:\Program Files\FirefoxPortable\FirefoxPortable.exe in path=D:\Program Files\FirefoxPortable\ LFN=FirefoxPortable.exe zerlegen zu können ("Filename X" kann das per GUI)
Da dacht ich mir folgendes:

Delphi-Quellcode:
var
 sPath, sFile : String;
begin
 sPath := ExtractFilePath( ParamStr(1) );
 sFile := ExtractFileName( ParamStr(2) );
 
 {
 UND HIER DIE ENV-VAR SETZEN

 SET PATH = sPATH
 SET LFN = sFILE

 }

end;
... tja, so einfach war das aber dann doch nich, wie man an dem Thread hier sieht :)

Vermutlich reicht es aber auch, wenn die EnvVar nur in der Sitzung zu Verfügung steht, weil sie ja gleich darauf wieder in einer Batch-Datei weiterverwendet wird. Nur, ist die Variable noch vorhanden, wenn ich meine Konsolenanwendung aus einer Batch ausrufe? Ne, oder? Weil meine Konsolenanwendung ja wieder in einer anderen Instanz als der, der Batch-Datei läuft? Hm...

Hansa 25. Jul 2007 07:46

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Zitat:

Zitat von Tyler
..Nur, ist die Variable noch vorhanden, wenn ich meine Konsolenanwendung aus einer Batch ausrufe? Ne, oder? Weil meine Konsolenanwendung ja wieder in einer anderen Instanz als der, der Batch-Datei läuft? Hm...

Sie ist in der Instanz vorhanden und zwar ab dann, wenn sie gesetzt ist, auch innerhalb des BAT-Laufes. Sie kann also innerhalb der BAT abgefragt werden. Geht ein neues Konsolen-Fenster auf, dann muss sie wieder neu gesetzt werden, weil es eine andere Instanz darstellt.

Christian Seehase 25. Jul 2007 20:45

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
Moin Hansa,


Zitat:

Zitat von Hansa
Sie ist in der Instanz vorhanden und zwar ab dann, wenn sie gesetzt ist, auch innerhalb des BAT-Laufes.

Falsch.
Sie ist nur innerhalb des Prozesses gültig, in dem sie gesetzt wird, und dessen Kindprozessen.
Die Konsole bekommt ihr Environment beim Start. Wird aus der Konsole heraus ein anderes Programm gestartet, so bekommt dieses nur ein e Kopie des Environments der Konsole, und kann darin Umgebungsvariablen setzen und löschen wie es gerade nötig ist.
Das Environment der Konsole wird dadurch in keinster Weise beeinflusst.

Wie schon geschrieben:
Microsoft sieht hier als Lösung nur das Erzeugen einer Batchdatei, die dann im Anschluss an das eigene Programm aufgerufen wird, damit die Umgebungsvariablen in der Konsole entsprechend gesetzt werden.
Und da ich nicht bereit war diese Lösung so zu akzeptieren, habe ich mir den anderen Weg überlegt :mrgreen:


Zitat:

Zitat von Hansa
Geht ein neues Konsolen-Fenster auf, dann muss sie wieder neu gesetzt werden, weil es eine andere Instanz darstellt.

Auch falsch ;-)
Startet man die Konsole aus einem eigenen Programm, z.B. per CreateProcess, kann sie das, sozusagen ganz normal, das eigene Environment als Kopie erhalten, wie schon oben beschrieben, indem man den Pointer auf einen Environment-Block weglässt, oder aber man baut ein Environment extra für den Aufruf zusammen, und übergibt dessen Pointer. Im ersten Falle würde die Konsole also die neu gesetzte Variable zur Verfügung haben, im zweiten hängt es davon ab, was man in den Block reinschreibt.
Wird die Konsole hingegen aus dem Explorer gestartet, und man hat die Variable so gesetzt, wie in dem verlinkten Beitrag beschrieben, steht der neuen Konsole die Variable zur Verfügung.

Allgemein:
Wird kein spezielles Environment für einen Kindprozess erstellt, so erbt dieser immer das Environment des Elternprozesses, und zwar als Kopie.
Wenn im Elternprozess, vor dem Start eines Kindprozesses, etwas am Environment geändert wird, sei es nun setzen, ändern oder löschen einer Variablen, so erhält der Kindprozess das geänderte Environment.

Einfach mal zum Ausprobieren.
Man nehmen ein Formular, einen Button, und folgenden Code:

Delphi-Quellcode:
uses shellapi;
{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
begin
  ShellExecute(0,'open','cmd.exe',nil,nil,SW_SHOWNORMAL);
  ShowMessage('Jetzt steht der Konsole das derzeitige System und Current-User Environment zur Verfügung.');
  SetEnvironmentVariable('NEUEVARIABLE','MIT EINEM WERT');
  ShellExecute(0,'open','cmd.exe',nil,nil,SW_SHOWNORMAL);
  ShowMessage('und jetzt ist etwas hinzugekommen');
end;
Sobald eine Konsole offen ist, einfach mal Set N eingeben.

Tyler 26. Jul 2007 12:17

Re: in KommandozeilenAnwendung DOS-Befehl ausführen
 
also wenn man ganz auf Nummer sicher gehen will, schreibt man die Variable wohl doch am Besten direkt in die Registry. Unter HLM/System/CurrentControlSet/Control/Session Manager/Enviroment werden die systemweiten Variablen gespeichert, und die lassen sich uach in jeder Konsole abrufen. ich denke, darauf werde ich dann zurückgreifen. :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:21 Uhr.
Seite 1 von 2  1 2      

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