CreateProcessAsUser(): fehlerhafter Fensteraufbau
-
Hallo,
Ich erzeuge aus einem Service heraus mit LogonUser() und CreateProcessAsUser() ein Prozess im Kontext des aktuell angemeldeten Benutzers.
Die Anwendung wird auch erfolgreich gestartet, jedoch wird mir das Fenster nicht richtig angezeigt (siehe Bild).
Der Dienst läuft unter dem lokalen Systemkonto.
Hier ein Auszug aus dem Code:
// Lege Startoptionen fest: STARTUPINFOW appStartupInfo; memset(&appStartupInfo, 0, sizeof(appStartupInfo)); appStartupInfo.cb = sizeof(appStartupInfo); // Melde Benutzer an: HANDLE userToken = NULL; if(!LogonUser( username, // Benutzername domain, // Domäne password, // Passwort LOGON32_LOGON_SERVICE, // Logontyp: Anmeldung als Service LOGON32_PROVIDER_DEFAULT, // Standard Logon-Provider &userToken) // Benutzer-Token ){ return false; } if (userToken == NULL) return false; // Starte Prozess: if(!CreateProcessAsUser( userToken, // Benutzer-Token NULL, // benutze Commandline appStartCmd, // Commandline NULL, // Process handle not inheritable NULL, // Thread handle not inheritable false, // inheritance priorityClass, // Prioritätsklasse NULL, // Environment NULL, // CurrentDirectory, &appStartupInfo, // Pointer to STARTUPINFO structure &appProcessInfo ) // Pointer to PROCESS_INFORMATION structure ){ ... }
Das bringt auch nix (richtige Windowsstation/richtiger Desktop) werden ja schon zugeordnet:
appStartupInfo.wShowWindow = SW_SHOW; appStartupInfo.dwFlags = STARTF_USESTDHANDLES; appStartupInfo.lpDesktop = L"Winsta0\\Default";
So sieht das Ergebnis dann aus
Für Ideen und Hinweise, wäre ich sehr dankbar!
Gruß Roger Wilco
-
Was ich vergaß:
Der Service läuft als interaktiver Dienst, wobei eine Lösung, in der mein Dienst nicht als interkativer Dienst läuft lieber wäre.
-
Vergiss diesen Ansatz. Spätestens unter Vista oder Server 2008 geht das nicht mehr.
-
Ja ich weiß, aber wir müssen das trotzdem so machen, da der Service Programme starten muss, die zur Zeit zwangsläufig Ihre UI zeigen müssen.
Später sollen die Programme die gestartet werden müssen als Dienst umgeschrieben werden und die UIs sollen entfallen. Zur Zeit aber wird diese Übergangslösung benötigt.
Ich habe auch inzwischen etwas gefunden:
Mittels WTSEnumerateSessions() sich eine Liste der Sessions holen (--> WTS_SESSION_INFO-Array) und diese dann nach dem gewünschten Benutzer durchsuchen (mittels WTSQuerySessionInformation). In der WTS_SESSION_INFO steht dann die SessionID des angemeldeten Benutzers.
Anschließend kann man mittels WTSQueryUserToken() über die nun erhaltende Session-ID den BenutzerToken erhalten und CreateProcessAsUser() aufrufen.
Der Dienst muss dafür nicht interaktiv sein!
Bedingung: Der Benutzer muss natürlich angemeldet sein.
Es geht aber noch einfacher:
WTSQueryUserToken( WTSGetActiveConsoleSessionId(), &userToken );
Dann wird das Programm in der gerade aktiven Session (die zur zeit mit der Maus/Tastatur verknüpften Session) geöffnet. Welcher Benutzer das gerade ist, weiß man dann allerdings nicht.
-
Hallo Roger,
jetzt läuft Deine UI aber nicht mehr unter dem User Account des Users, den Du oben noch mit LogonUser() angemeldet hast (UserA), sondern unter dem User Account des gerade eingeloggten Users (UserB).
Gibt es denn eine Möglichkeit, den Prozess so zu starten, daß er unter dem Account von UserA läuft, aber die GUI trotzdem auf dem Desktop von UserB angezeigt wird?
Unter XP ging das noch einwandfrei. Dazu gab es ein Beispiel von Microsoft, in dem die ACLs von Winsta0\Default so gesetzt wurden, daß UserA darauf zugreifen darf, und dann wurde der Prozess einfach per LogonUser(), CreateProcessAsUser() gestartet.
Unter Vista funktioniert das nicht mehr. Kann mir wer sagen, wie es da geht?
-
Man trennt Service und UI.
Der Service läuft im Hintergrund und über ein spezielles Programm steuert man diesen. Diese zweite Programm kommuniziert über Standard-IPC Methoden.
-
Martin Richter schrieb:
Man trennt Service und UI.
Der Service läuft im Hintergrund und über ein spezielles Programm steuert man diesen. Diese zweite Programm kommuniziert über Standard-IPC Methoden.Bitte lies nochmal, worum es hier geht. Um das, was du schreibst, geht es nämlich nicht.
Ich habe mittlerweile einen Weg gefunden, der allerdings sehr unelegant ist:
Ich kann vom Service aus ein Programm starten, daß Zugriff auf den sichtbaren Desktop erhält und unter dem User Account des gerade eingeloggten Users läuft. Dieses Programm kann dann per CreateProcessWithLogonW() die eigentliche Applikation starten, die dann unter dem Account des Zielusers läuft und seine GUI trotzdem auf dem Desktop anzeigen kann.
Wenn das alles von dem Service ausginge, wäre es natürlich wesentlich schöner.
-
Mit dem oben von mir dargestellten Weg, kannst Du von einem Windows-Dienst aus ein Programm starten, welcher (Process+GUI) im Kontext eines angemeldeten Users läuft und der User kann die GUI auch sehen.
@Martin Richter: Du hast schon vollkommen Recht und die Gründe liegen auf der Hand, nur bin ich zum Beispiel zur Zeit dazu gezwungen, von einem Service aus mehrere Processe zu starten (die nicht mit dem Service komunizieren!), dessen GUIs (die GUIs der Programme, nicht des Service!) der User sehen können muss. Bei mir haben die gestarteten Prozesse und deren GUIs nichts mehr mit dem Service zu tun.
Schön wäre eine Variante, wo die Programme bereits vor dem User-Logon gestartet werden und nach dem User-Logon dann auch sichtbar sind.