コンソールアプリケーションとサービスの両方として実行できるC#/。NETプログラムがあります。現在、コンソールアプリケーションとして起動するためのコマンドラインオプションを提供していますが、それは避けたいと思います。
プログラムがサービスとして開始されているかどうかをプログラムで検出することはできますか?
純粋なWin32の場合、StartServiceCtrlDispatcherを使用してサービスとして開始し、ERROR_FAILED_SERVICE_CONTROLLER_CONNECTが返された場合はコンソールにフォールバックできますが、失敗した場合はSystem.ServiceProcess.ServiceBase.Run()がエラーダイアログをポップアップし、エラーを通知せずに戻ります。プログラムに。
何か案は?
ラスムス、 これは前の質問です 。
回答から、最も一般的な方法は、単純なコマンドラインオプションを使用するか、try catchブロックでコンソールオブジェクトにアクセスしてみることです(サービスでは、コンソールはプロセスに接続されておらず、アクセスしようとすると例外がスローされます) 。
または、サービスのテスト/デバッグで問題が発生した場合は、コードを別のdllアセンブリに移動し、別のテストハーネス(winforms/consoleなど)を作成します。
(ジョナサンが質問の最後に彼の解決策を追加したことに気づきました。)
Environment.UserInteractive 魔法をかけます。
ProcessオブジェクトのSessionIdプロパティを試してみることをお勧めします。私の経験では、プロセスがサービスを実行している場合、SessionIdは0に設定されます。
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
const int STD_OUTPUT_HANDLE = -11;
IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (iStdOut == IntPtr.Zero)
{
app.RunAsWindowsService = true;
}
// Run as Service
if (runAsWindowsService)
{
// .....
ServiceBase.Run(myService);
}
else
{
// Run as Console
// Register Ctrl+C Handler...
}
親プロセスの検索について この回答 のParentProcessUtilities構造体を使用すると、次のことができます。
static bool RunningAsService() {
var p = ParentProcessUtilities.GetParentProcess();
return ( p != null && p.ProcessName == "services" );
}
親プロセスのプロセス名には、拡張子「.exe」が含まれていないことに注意してください。
私は試していませんが、 Process.GetCurrentProcess が役立つ可能性があります-コンソールモードでは、プロセス名は実行可能ファイルと同じになりますが、期待しています(もう一度確認してください! )サービスとして実行する場合は異なります。
これが機能するかどうかはわかりませんが、 this コードでPInvokeを使用して、親が「services.exe」であるかどうかを確認することをお勧めします。
Console.IsErrorRedirected をチェックして、コンソールアプリケーションを使用しているかどうかを検出することになりました。コンソールアプリの場合は「false」を返し、テストした非コンソールアプリの場合は「true」を返しました。 IsOutputRedirected を使用することもできます。
これらが正確でない状況があると思いますが、これは私にとってはうまくいきました。