アプリケーションをリモートで実行および停止できる Windows サービスを作成しました。これらのアプリケーションは CreateProcess を使用して実行されます。ほとんどのアプリケーションはバックエンド処理のみを実行するため、これは私にとってはうまくいきます。最近、現在のログイン ユーザーに GUI を表示するアプリケーションを実行する必要があります。サービスが現在アクティブなデスクトップを見つけてその上で GUI を実行できるようにするには、C++ でどのようにコーディングすればよいですか?
9 に答える
Roger Lipscombe の答えは、WTSEnumerateSessionsを使用して適切なデスクトップを見つけ、次にCreateProcessAsUserを使用してそのデスクトップでアプリケーションを起動する (デスクトップのハンドルをSTARTUPINFO構造体の一部として渡す) ことです。
ただし、これを行うことは強くお勧めしません。多くのアクティブ ユーザーがいるターミナル サーバー ホストなどの一部の環境では、どのデスクトップが「アクティブ」なのかを判断するのは簡単ではなく、不可能な場合もあります。
しかし、最も重要なことは、アプリケーションがユーザーのデスクトップに突然表示される場合、これは悪いタイミングで発生する可能性が非常に高いということです (ユーザーが予期していなかったか、セッションが開始されていないときにアプリを起動しようとしていたため)。まだ完全に初期化されていない、シャットダウン中など)。
より従来的なアプローチは、グローバル スタートアップ グループにサービス用の小さなクライアント アプリへのショートカットを配置することです。このアプリは、すべてのユーザー セッションとともに起動し、ユーザーの資格情報、セッション、および/またはデスクトップをジャグリングすることなく、(必要に応じて) 他のアプリを開始するために使用できます。
また、このショートカットは、必要に応じて管理者が移動/無効にすることができます。これにより、他の Windows アプリで使用される標準から逸脱しないため、アプリケーションの展開がはるかに簡単になります...
別のユーザー コンテキストで実行されている GUI プログラムを開くことは、一般にShatter Attackとして知られているセキュリティ上の脆弱性であるため、短い答えは「あなたはしない」です。
この MSDN の記事をご覧ください: Interactive Services。サービスがユーザーと対話するためのいくつかのオプションを提供します。
つまり、次のオプションがあります。
WTSSendMessage 関数を使用して、ユーザーのセッションでダイアログ ボックスを表示します。
別の隠し GUI アプリケーションを作成し、CreateProcessAsUser 関数を使用して、対話型ユーザーのコンテキスト内でアプリケーションを実行します。名前付きパイプなど、何らかのプロセス間通信 (IPC) の方法を介してサービスと通信するように GUI アプリケーションを設計します。サービスは、GUI アプリケーションと通信して、いつ GUI を表示するかを伝えます。アプリケーションは、サービスが適切なアクションを実行できるように、ユーザー インタラクションの結果をサービスに返します。適切なアクセス制御リスト (ACL) を使用しない限り、IPC はネットワーク経由でサービス インターフェイスを公開できることに注意してください。
このサービスをマルチユーザー システムで実行する場合は、各セッションで実行されるようにアプリケーションを次のキーに追加します: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run。アプリケーションが IPC に名前付きパイプを使用する場合、サーバーはセッション ID に基づいて各パイプに一意の名前を付けることで、複数のユーザー プロセスを区別できます。
何人かが WTSEnumerateSessions と CreateProcessAsUser を提案しました。ログインしているユーザーを 1 人だけターゲットにしたいと言ったのに、なぜ誰も WTSGetActiveConsoleSessionId を提案しなかったのだろうか。
ただし、CreateProcessAsUser を提案するのは確かに正しい人もいます。あなたが言ったようにプレーンな古い CreateProcess を呼び出すと、アプリケーションの GUI はユーザーの特権ではなく、サービスの特権で実行されます。
WTSEnumerateSessions および CreateProcessAsUser。
その問題 Session 0 、 Interactive Services 、 Windows Service Allow Service To Interact With Desktop on Windows 7 または Windows Vista
この記事を読むことができます http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
ここで説明してみます Windows 7で動作しています
Win2K、XP、および Win2K3 では、コンソール ユーザーは、サービスが存在する同じセッションであるセッション 0 にログオンします。サービスが対話型として構成されている場合、ユーザーのデスクトップに UI を表示できます。
ただし、Vista では、ユーザーはセッション 0 にログオンできません。サービスから UI を表示するのは少しトリッキーです。WTSEnumerateSessions APIを使用してアクティブなセッションを列挙し、コンソール セッションを見つけて、そのユーザーとしてプロセスを作成する必要があります。もちろん、それを行うにはトークンまたはユーザー資格情報も必要です。このプロセスの詳細については、こちらをご覧ください。
重要なサービスは、Windows Vista以降、ユーザーと直接対話することはできません。したがって、「対話型サービスの使用」というタイトルのセクションで説明した手法は、新しいコードでは使用しないでください。
これは、http://msdn.microsoft.com/en-us/library/ms683502 (VS.85).aspxから取得されます。
ログインしているユーザーが1人だけである限り、そのユーザーのデスクトップに自動的に表示されると思います。
とにかく、サービスに exe を開始させるときは十分に注意してください。
exe を含むフォルダーへの書き込みアクセスが制限されていない場合、ユーザーはその exe を他のプログラムに置き換えることができ、システム権限で実行されます。たとえば、cmd.exe (すべての Windows システムで利用可能) を考えてみましょう。次にサービスがexeを起動しようとすると、システム権限を持つコマンドシェルが表示されます...
サービスから GUI を起動すると、現在アクティブなデスクトップに表示されます。
ただし、サービスのアクセス許可を調整した場合のみ:デスクトップとの対話を許可する必要があります。