Visual StudioでASP.NET WebプロジェクトでProcess.Startメソッドで実行可能ファイル(拡張子 .exe)が起動しない場合の対処法を備忘録的に投稿します。
Process.Startで別アプリの起動
Visual Studioのデバッグ時には次のコードで、別アプリの起動できてもWindowsサービスやIISにホスティングした際に動作しない場合があります。
public void Execute(string filename)
{
ProcessStartInfo pi = new ProcessStartInfo();
pi.UseShellExecute = true;
pi.FileName = filename;
Process.Start(pi);
}
ユーザーセッションで起動
原因はアプリが動作しているのがシステム(LocalSystemなど)の場合に、ユーザーインターフェイスを持つアプリが起動できないような制限があるためです。
なので、Win32APIの[CreateProcessAsUser]関数を利用すると起動が出来る場合があります。
具体的には、次のような構造体とWin32APIを利用するための[DllImport]を追加します。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public int cb;
public IntPtr lpReserved;
public IntPtr lpDesktop;
public IntPtr lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public ushort wShowWindow;
public ushort cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[DllImport(@"ADVAPI32.dll", CharSet = CharSet.Unicode)]
public extern static Int32 CreateProcessAsUser(IntPtr hToken, IntPtr lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, Int32 bInheritHandles, UInt32 dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport(@"Kernel32.dll")]
public extern static Int32 CloseHandle(IntPtr hObject);
[DllImport(@"Kernel32.dll")]
public extern static UInt32 WTSGetActiveConsoleSessionId();
[DllImport(@"WTSAPI32.dll")]
public extern static Int32 WTSQueryUserToken(UInt32 SessionId, out IntPtr phToken);
実際にアプリを起動する場合は、こんな感じで呼び出します。
public void Execute(string filename)
{
uint sessionId = WTSGetActiveConsoleSessionId();
IntPtr userToken;
if (WTSQueryUserToken(sessionId, out userToken) == 0)
{
return;
}
STARTUPINFO startupInfo = new STARTUPINFO();
startupInfo.cb = Marshal.SizeOf(startupInfo);
PROCESS_INFORMATION pi;
int result = CreateProcessAsUser(
userToken,
IntPtr.Zero,
filename,
IntPtr.Zero,
IntPtr.Zero,
0,
0,
IntPtr.Zero,
System.IO.Directory.GetCurrentDirectory(),
ref startupInfo,
out pi);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(userToken);
}
起動時に利用されているユーザーのプロセスでアプリが実行されるので、[Windows サービス]からユーザーインタフェイスを持つアプリが表示されるようになります。
まとめ
Visual StudioでASP.NET WebプロジェクトでProcess.Startメソッドで実行可能ファイル(拡張子 .exe)が起動しない場合の対処法について書きました。
WindowsサービスやIISなどでホスティングしたASP.NET Core Webアプリは、ユーザーとは別のプロセス(システムなど)で動作しているため、ユーザーインターフェイスを持つアプリの起動が制限されます。
そのため[CreateProcessAsUser]などのWin32APIでユーザーセッションで動作するように起動する必要があります。
ASP.NET WebプロジェクトでProcess.Startメソッドで実行可能ファイル(拡張子 .exe)が起動しない人の参考になれば幸いです。
スポンサーリンク
最後までご覧いただき、ありがとうございます。