Win32 CreateProcess: Wann wird CREATE_UNICODE_ENVIRONMENT * wirklich * benötigt?

9

Die CreateProcess -Dokumentation enthält (meine hervorgehobene Hervorhebung):

  

lpEnvironment [in, optional]

     

[...] Wenn der Umgebungsblock, auf den lpEnvironment verweist, Unicode-Zeichen enthält, stellen Sie sicher, dass dwCreationFlags CREATE_UNICODE_ENVIRONMENT enthält. Wenn dieser Parameter NULL ist und der Umgebungsblock des übergeordneten Prozesses Unicode-Zeichen enthält, müssen Sie außerdem sicherstellen, dass dwCreationFlags CREATE_UNICODE_ENVIRONMENT enthält.

Ist MSDN falsch und überschätzt die Bedeutung der Flagge oder ist das eine echte Anforderung?

Ich habe Code gesehen, der niemals die Flagge setzt und scheint zu funktionieren, aber der paranoide Teil von mir möchte 100% mit dem übereinstimmen, was MSDN sagt. Wenn ich das sage, bin ich mir nicht sicher, ob Sie wirklich den Regeln von MSDN folgen können, ohne zu extrem zu werden.

Ich muss CREATE_UNICODE_ENVIRONMENT setzen (oder nicht setzen), wenn lpEnvironment NULL ist, erscheint mir lächerlich:

  1. Wenn ich einen Umgebungsblock nicht übergebe, muss CreateProcess den Block selbst erhalten. In diesem Fall ist es in einer besseren Position als ich, um den Typ des Blocks zu kennen.

  2. Woher weiß ich, ob der Block tatsächlich Unicode-Zeichen enthält?

    Soll ich den Block holen und auf Zeichen außerhalb der aktuellen Codepage prüfen? (Ich gehe davon aus, dass MSDN hier "Unicode-Zeichen" bedeutet.)

    Wenn ich den env-Block bekommen muss, kann ich ihn auch in lpEnvionment statt NULL übergeben, also warum auch NULL erlauben?

    Den env-Block zu erhalten und zu inspizieren, scheint für jeden Aufrufer von CreateProcess eine wahnsinnige Voraussetzung zu sein; Es ist sicherlich etwas, das die API selbst behandeln sollte.

  3. Wenn "Elternprozess" heißt, bedeutet das sogar meinen Prozess, der kurz davor steht, ein neuer Elternteil zu werden, oder heißt es Elternteil meines Prozesses ? Mein erstes Lesen von MSDN ließ mich denken, dass ich irgendwie sagen musste, ob der CreateProcess-Aufruf, der mein Prozess gestartet hatte, einen ANSI- oder Unicode-Umgebungsblock passiert hatte, aber das ist sicherlich nicht der Fall.

    >

    Ich gehe davon aus, dass auf NT-basierten Betriebssystemen alle Prozesse über einen Unicode-env-Block verfügen, der bei der Prozessgenerierung von ANSI konvertiert wird und Prozesse nicht an den Datenblock gebunden sind, der an CreateProcess übergeben wurde -is.

    (Vielleicht ist das Ganze ein Rest von den Win9x-Tagen, wo das Betriebssystem selbst kein Unicode war? Selbst dann kann ich nicht sehen, wie Anwendungscode die Entscheidung besser machen könnte als das Betriebssystem selbst warum es erwartet werden sollte.)

  4. Sowie Code, der niemals das Flag setzt, habe ich Code gesehen, der es immer setzt, wenn UNICODE zur Kompilierzeit definiert wurde. Das macht keinen Sinn, wenn die Anforderung auf dem steht, was zur Laufzeit in dem env-Block ist und wann der Code in einer DLL sein kann, die in einen fremden Prozess geladen wird.

    Der env-Block ist prozessweit, so dass UNICODE, das zur Kompilierzeit definiert wird, irrelevant erscheint.

  5. Wenn es nur darum geht, ob ich CreateProcessA oder CreateProcessW aufrufen soll, dann sollte das Flag implizit sein, wenn der Block NULL ist, also ergibt das auch keinen Sinn.

In meinem eigenen Code habe ich entschieden, die Frage zu vermeiden und immer eine Unicode-Kopie des Umgebungsblocks (über GetEnvironmentStringsW) zu erhalten, immer an CreateProcess weiterzugeben und immer CREATE_UNICODE_ENVIRONMENT zu setzen. Das ist die einzige Möglichkeit, die zu 100% korrekt ist, basierend auf dem, was MSDN sagt.

Aber was ich mache, ist sicherlich überflüssig. CreateProcess kann nicht so dumm sein, oder?

Auf der anderen Seite ist dies CreateProcess, von dem wir sprechen. Es ist nicht die am besten gestaltete API und hat eine Reihe anderer Fallstricke (von oben):

  1. Fehlgeschlagen, wenn die Argument-Zeichenfolge const ist, weil sie direkt geändert wird.
  2. Das erste Argument optional zu machen und damit die Leute dazu zu verleiten, den exe-Pfad im zweiten Argument zu zitieren.
  3. Erfordert den korrekt zitierten exe-Pfad im zweiten Argument, auch wenn es explizit im ersten Argument angegeben ist.

Vielleicht ist es also nicht richtig anzunehmen, dass es sich intelligent verhält oder sich wahrscheinlich um Aufgaben für den Anrufer kümmert ...

Ich weiß nicht, ob ich den paranoiden Müll aus meinem eigenen Code entfernen oder ihn zu all dem anderen Code hinzufügen soll, den ich sehe. Argh. : -)

HINZUGEFÜGT 18 / Nov / 2010:

Es scheint, dass das Flag irrelevant ist, wenn der env-Block NULL ist, zumindest in Windows 2000 bis Windows 7. Siehe meinen Test unten.

Offensichtlich macht dies nicht den Schluss, dass die Flagge in allen zukünftigen Betriebssystemen immer irrelevant sein wird, aber ich kann wirklich nicht sehen, wie es anders sein könnte.

Nehmen wir an, wir haben Großvater, der Parent erstellt hat, der gerade Child anlegen soll:

  • Wenn das Betriebssystem immer den env-Block für Parent als Unicode speichert - nachdem er während der Erstellung von Parent in ANSI konvertiert wurde, wenn Grandparent einen ANSI-Block übergeben hat -, wäre CreateProcess irrtümlich, um das Flag zu beachten wenn Parent einen NULL-Block übergibt. CreateProcess muss wissen, dass der Block, den Child erbt, IMMER Unicode ist.

  • Alternativ kann OS den env-Block für Parent genau so speichern, wie er von Grandparent stammt. (Dies scheint unwahrscheinlich, aber es ist möglich.) In diesem Fall hat Parent keine Möglichkeit festzustellen, welche Art von Block Grandparent bestanden hat. Erneut muss CreateProcess den Typ des Blocks kennen und das Flag ignorieren.

Hier ist ein Test, den ich heute Morgen geschrieben habe und der einen Child-Prozess auf verschiedene Arten startet und dem Child-Prozess einen env-var (nur die "OS" -Variable der Kürze halber) gibt:

%Vor%

Dies gibt aus:

%Vor%

Wenn der env-Block NULL ist, spielt das Flag keine Rolle.

Wenn es nicht NULL ist, spielt das Flag eine Rolle, da CreateProcess gesagt werden muss, was hinter dem void * steht (aber das ist offensichtlich und die Frage betrifft nur den NULL-Fall).

Kann jemand an irgendein Szenario denken, bei dem die Flagge möglicherweise eine Rolle spielt, wenn der env-Block NULL ist? Und in diesem Szenario, wie würde die App möglicherweise den korrekten Wert der Flagge besser kennen als das Betriebssystem selbst?

    
Leo Davidson 17.11.2010, 15:48
quelle

1 Antwort

5

Beachten Sie, dass in der Deklaration der Funktion CreateProcess der Parameter lpEnvironment deklariert ist LPVOID .

Was bedeutet das? Dies bedeutet, dass Sie die Ansi / Unicode-Version von CreateProcess function verwenden und sie in einer beliebigen Kombination in einem Ansi / Unicode-Versionsumgebungsblock übergeben können. Insbesondere können Sie die Unicode-Version von CreateProcess verwenden und den Ansi-Umgebungsblock übergeben und umgekehrt.

Also ist das Setzen von CREATE_UNICODE_ENVIRONMENT erforderlich , wenn Sie tatsächlich den Unicode-Umgebungsblock verwenden, weil es keine andere konventionelle Möglichkeit gibt (abgesehen von einigen hässlichen Heuristiken) erkenne, dass es Unicode ist.

Nun zu Ihren Fragen:

  1. Wenn Sie den Umgebungsblock nicht explizit übergeben, hat der neu erstellte Prozess anfangs die gleichen Umgebungsvariablen wie sein Ersteller. Es sei denn, Sie müssen eine extra Konfiguration für den neu erstellten Prozess vornehmen - nichts mehr als das ist erforderlich.

  2. Wenn Sie den Umgebungsblock an den neu erstellten Prozess übergeben, müssen Sie ihn entweder manuell erstellen oder von irgendwoher abrufen. In beiden Fällen müssen Sie wissen , ob es Unicode ist.

  3. Elternteil des neuen Prozesses ist sein Schöpfer. In Ihrem speziellen Fall - Ihr Prozess.

  4. Dies hängt ausschließlich davon ab, wie der Umgebungsblock erstellt wird. Wenn Sie das, was Sie erhalten, immer weitergeben, indem Sie GetEnvironmentStrings aufrufen, dann ist es in Unicode, wenn Sie mit UNICODE definiert haben. Dann sollten Sie CREATE_UNICODE_ENVIRONMENT setzen, wenn Sie in Unicode kompilieren. Auf der anderen Seite, wenn Sie es manuell erstellen - Sie können es in Unicode konstruieren, auch wenn Sie nicht in Unicode kompilieren. Daher sollten Sie CREATE_UNICODE_ENVIRONMENT entsprechend der Konstruktion des Umgebungsblocks einstellen, nicht gemäß der Definition der Kompilierung.

  5. Wie bereits erwähnt, können sowohl CreateProcessA als auch CreateProcessW mit einem Ansi oder Unicode-Umgebungsblock arbeiten. Dies ist genau der Grund, warum dieses Flag erforderlich ist.

valdo 17.11.2010 17:14
quelle