![]() |
Nachricht auf allen Desktops anzeigen - und wieder schließen
Hi Leute, ich habe ein Problem vor dem ich bereits seit einer Woche sitze. Mittlerweile sind mir die Lösungsansätze ausgegangen, vielleicht weiß ja jemand den "Trick", den ich benötige.
Das Problem bezieht sich rein auf Windows Vista. Unter Windows XP hat jeder der Lösungsansätze funktioniert. Drum poste ich jetz auch mal keien Code, da das Problem bei der Vorgehensweise sitzt und nicht im Code selbst. Aufgabe: Ich habe einen Dienst unter dem lokalen SYSTEM Account laufen. Dieser Dienst soll eine Nachricht z.B. MessageBox in JEDER aktiven Terminal-Session, der interaktiven Console sowie dem Logon-Screen anzeigen. Anschließend muss der Dienst dieses Fenster aber auch automatisch Schließen können. Und genau beim Schließen liegt das Problem! Lösungsansatz 1: Über WTSEnumSessions alle aktiven Terminal-Sessions auslesen. An jede Session dann per WTSSendMessage und MB_SERVICE_NOTIFICAION eine Nachricht schicken. Funktioniert soweit Prima - sowohl XP und Vista zeigen die Nachricht überall wie gewünscht an. Problem ist nun das Fenster wieder zu schließen: Ich habe probiert über EnumDesktops / OpenDesktop / EnumDesktopWindows alle Fenster durchzulaufen und das Entsprechende dann per PostMessage->WM_CLOSE zu schließen. Unter XP kein Problem. Unter Vista gibts aber, dank der Isolation der Session 0, keinen Zugriff auf die MessageBox. Auch SetThreadDesktop hilft nicht bzw schlägt fehl. Lösungsansatz 2: Habe nun einen Trick versucht: Die Funktion welche alle Desktops/Fenster durchläuft und das Nachrichtenfenster schließen soll, wurde in eine separate Exe ausgelagert. Anschließend wird für jede aktive Terminal-Session über WTSQueryUserToken der User ermittelt und mit CreateProcessAsUser diese Schließen-Exe unter jedem angemeldeten User gestartet. Geht unter Vista leider auch nicht, Die EnumDesktopWindows listet die MessageBox nicht auf. Lösungsansatz 3: Die Nachricht nicht per WTSSendMessage sondern als eigene Form anzeigen. EnumDesktops ermittelt alle aktiven Desktops. Anschließend wird für jede anzuzeigende Nachricht ein Thread gestartet, welcher mit SetThreadDesktop den jeweiligen Desktop setzt und die Form anzeigt. Anschließend wartet der Thread auf eine interne Nachricht um sein eigenes Fenster wieder zu schließen. Funktioniert unter XP wieder wunderbar. Unter Vista wird der Default-Desktop zwar übernommen, das Fenster erscheint allerdings nicht. Ich bin am verzweifeln. Weiß evtl jemand noch einen Lösungsansatz? Für Ideen wäre ich sehr dankbar! md |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Die Ansätze 1 und 3 können gar nicht funktionieren: Die TS eines Prozesses kann nicht geändert werden.
Der Ansatz 2 ist korrekt. Hast du in der StartupInfo-Struktur Desktop und Window-Station angegeben? Hast du im Token die SessionID gesetzt? |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Merci für die flotte antwort. :thumb:
Ne hab ich nicht gemacht :oops: Werds morgen mal probieren und gib dann bescheid. Für heute hab ich erstmal genug :lol: |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
> Die TS eines Prozesses kann nicht geändert werden.
Ich bin der Meinung, dass ich darüber schon was gelesen habe (ging evt. via einer WTS Funktion). Ich würde in jede aktive Session eine ShowAndCloseMsgbox.exe via CreateProcessAsUser injizieren. Datenaustausch zum Service via named pipes. |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Ja und? Die TS eines neuen Prozesses wird mit dem Token festgelegt - sobald der Prozess läuft, ist sie fest. Nichts anderes habe ich behauptet.
|
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Sagt mal kann mann nicht vieleicht das Massage-Fenster mit dem WinSpy Programm von dem einem hier im Forum (sorry für das anreden, aber ich weiß grad net wer das nochmal war) verwenden und mal starten und versuchen das Handle rauszufinden und dan mit ShowWindow(Handle, sw_close); (soviel ich jetzt aus Kopf weiß) wieder schließen?????
Oder bin ich da voll auf dem Holzweg :oops: |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Schreibe einen eigenen Prozess, der die Nachricht anzeigt und dann sich später selbst beendet.
Und dazu nehme: Jwscl implementiert ![]() Die aktualisierte Version im SVN trunk Ordner funktioniert auch unter Windows 2000 Workstation.
Delphi-Quellcode:
{[B]JwCreateProcessInSession[/B] creates a new process in a user's session using various ways to
achieve success. This procedure needs JwInitWellKnownSIDs to be called. To run a process in another session you need to have SYSTEM rights. @param ApplicationName defines the application to be run in the session @param CommandLine defines the parameters for the application @param CurrentDirectory defines the start folder of the app. @param SessionID defines the target session where the new application is to be started. @param CreationFlags defines creation flags that are delivered to CreateProcess parameter with same name @param Desktop defines the target windowstation and desktop name. If empty the default target is "winsta0\default" @param StartupInfo defines startup info delivered to to CreateProcess parameter with same name. Don't forget to initialize the structure first before calling this procedure. <code lang="delphi> ZeroMemory(@StartupInfo, sizeof(StartupInfo)); </code> @param WaitForProcess defines whether the procedure should wait for the process to end and clean up all allocated resources or just return to the caller. In last case the caller is responsible to free the returned token, the environment block and the users profile @param Output contains returned data in case parameter WaitForProcess is false. The caller is responsible to free the contained member allocation @param LogServer receives a log server instance. It is used to log events for mostly debugging purposes. If this parameter is nil, no events are logged raises EJwsclProcessIdNotAvailable: will be raised if no token could be found for the given SessionID EJwsclNilPointer: will be raised if JwInitWellKnownSIDs was not called before } |
OT: Nachricht auf allen Desktops anzeigen - und wieder schli
Zitat:
|
Re: OT: Nachricht auf allen Desktops anzeigen - und wieder s
Zitat:
und dann nicht mehr. |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Klar lässt sich das Token ändern. Ein eventuelles Ändern der Session-ID wirkt sich aber nicht auf den Prozess aus. Es würde zu arg abstrusen Effekten führen, wenn man die Session eines Prozesses ändern könnte, während er läuft. Denk nur mal daran, dass er ein Handle zu einem Session-lokalen Objekt (z.B. Desktop) haben könnte. Dieses Handle verlöre seinen Sinn.
|
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Wie gesagt, ein Prozess kann nicht das Token eines anderern Prozesses nachträglich ersetzen unter Vista. Es gibt eine 5.
Wenn die SessionID gesetzt wurde und der Prozess läuft, liefert SetTokenInformation einen Fehler zurück. |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Danke für den Hinweis!
Eines meiner Programme benutzt nämlich ZwSetInformationProcess um sein Token mit bestimmten Rechten auszustatten. Und tatsächlich Vista sagt nur c0000005 dazu. :oops: |
geschafft
Zitat:
Das Programm startet sich 1x pro Terminal Session mit dem Parameter STOPX selbst. Durch den Start mit diesem Parameter werden im entsprechenden Kontext alle Fenster der entsprechenden Session durchlaufen. Da die WTSSendMessage MB_SERVICE_NOTIFICATION nun auch die MessageBox im Login-Screen und beim "gesperrtem" Bildschirm anzeigt, muss ich es noch irgendwie schaffen an diese Fenster zu kommen. Ich lasse vom Hauptprozess unter Session0 / System nochmal zusätzlich alle verfügbaren WindowStations und Desktops nach der MessageBox durchsuchen. Allerdings wird sie nicht gefunden. Ich werde da noch probieren, einen zusätzlichen Prozess unter expliziter Angabe der WinSta0\Winlogon und WinSta0\Disconnect zu starten.
Delphi-Quellcode:
hier der Code für SetTokenSessionId:
for i := 0 to Length(SessionInfos) - 1 do begin
UserToken := QueryUserToken(SessionInfos[i].SessionId); ZeroMemory(@SI, SizeOf(SI)); ZeroMemory(@PI, SizeOf(PI)); SI.lpDesktop := nil; SI.dwFlags := STARTF_USESHOWWINDOW; SI.wShowWindow := SW_HIDE; SI.cb := SizeOf(si); DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, nil, SecurityImpersonation, TokenPrimary, DuplicatedToken); if(DuplicatedToken <> 0) then begin SetTokenSessionId(DuplicatedToken, SessionInfos[i].SessionId); CreateProcessAsUser(DuplicatedToken,PAnsiChar(ParamStr(0)) , PAnsiChar(ParamStr(0) + ' STOPX'), nil, nil, false, CREATE_NEW_CONSOLE, nil, nil, SI, PI); end; CloseHandle(UserToken); CloseHandle(DuplicatedToken); end;
Delphi-Quellcode:
{$EXTERNALSYM _SetTokenInformation}
function _SetTokenInformation(TokenHandle: Cardinal; TokenInformationClass: Integer; TokenInformation: PDWORD; TokenInformationLength: DWORD): bool; stdcall; function SetTokenSessionId(UserToken: Cardinal; SessionId: integer): bool; implementation function _SetTokenInformation; external 'Advapi32.dll' name 'SetTokenInformation'; function SetTokenSessionId(UserToken: Cardinal; SessionId: integer): bool; var Information: DWORD; begin Information := DWORD(SessionId); result := _SetTokenInformation(UserToken, 12, @Information, Cardinal(SizeOf(Information))); end; |
Re: geschafft
Zitat:
Unter diesen Desktops werden keine Fenster gefunden. Hat jemand ne Idee wie ich diese auch noch zum schließen bringe? |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Wenn du pro Session eh schon ein Programm hast, dann kannst du die DialogBox auch gleich selbst anzeigen :D
Schau dir mal an, von welchem Prozess der Dialog angezeigt wird. Wenn der Prozess Systemrechte besitzt, dann wirst du es nicht finden, wenn deine Suche nicht auch von einem Prozess mit Sysrechten ausgeführt wird. |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Laut den Infos von hier:
![]() STARTUPINFO lpDesktop auf Winsta0\Winlogon setzen und über SetTokenInformation die Session des UserTokens auf die entsprechende Session setzen würde ich jetzt sagen. Aber wie geht das mit User SYSTEM? QueryUserToken auf Session 0 liefert einen Token 0 zurück. Diesen dupliziert ergibt auch 0 ;-) Entsprechen kann ich keine andere Session über SetTokenInformation setzen und den Schließen-Prozess damit starten. Hat SYSTEM überhaupt ein UserToken? Oder bin ich da auf dem Holzweg? :| |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Wenn dein Service als System läuft, hat er auch ein entsprechendes Token. Also kannst du einfach dein Prozess-Token duplizieren und das Duplikat verwenden, nachdem du dort die Session-ID gesetzt hast.
|
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
vorsicht: WTSQueryUserToken liefert unter xp das user token zurück.
|
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
es ist zum verzweifeln :(
Jetz paßt alles soweit, die MEssageBox wird überall wieder geschlossen bis auf einen Fall: Wenn mehrere Sessions unter Vista aktiv sind, wird das Fenster zwar in jeder session geschlossen. Scheinbar überwacht aber WTSSendMessage jedes Nachrichtenfenster, ob es automatisch geschlossen wird ohne dass es der User sehen konnte. Also quasi Wenn es in einer Session die grad nicht verbunden ist, geschlossen wird. Anders kann ichs mir nicht erklären. Das Fenster wird laut Debug-Outputs geschlossen erscheint aber sofort drauf wieder mit neuem Handle. Irgendwie eine undokumentierte Funktion von WTSSendMEssage? eine Lösung wüsst ich für den Fall noch. Ich lass den Schließen-Prozess so lange im Kreis laufen bis keine MessageBox mehr existiert. Der prozess läuft quasi dann so lange bis sich der angemeldete Benutzer zu der Session verbindet. Anschließend kann das Fenster dann geschlossen werden. Echt frustrieren das. Mal sehen obs so dann auch wirklich zu 100% alle existierenden Nachrichtenfenster schließen kann, oder ob der 281 Stolperstein auftaucht :wall: |
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Warum machst du nicht einfach deinen eigenen MessageBox Prozess?
|
Re: Nachricht auf allen Desktops anzeigen - und wieder schli
Momentan klappts jetzt aber mit dem Prozess der so lange läuft bis die Session aktiv wird und das Fenster sich nicht wieder von alleine öffnet. Wenn das auch nicht funktioniert hätte bzw nochmal n neues Hindernis gekommen wär hätt ichs mit der eingenen MessageBox gemacht.
Man muss es halt erst rausfinden dass WTSSendMessage so reagiert. Dachte immer es liegt am User/Desktop Kontext :/ Wärs denn möglich mit einer eigenen Message-Box das Fenster auch im Login-Screen und dem Gesperrt-Desktop anzeigen zu lassen, so wie WTSSendMessage mit MB_SERVICE_NOTIFICATION das tut? Evtl wird das ganze ja mal erweitert. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz