CreateProcessAsUser,C#写的windows服务弹框提示消息或者启动子进程-飞外

服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分。我们可以把服务想像成一种特殊的应用程序,它随系统的 开启~关闭 而 开始~停止 其工作内容,在这期间无需任何用户参与。Windows 服务在后台执行着各种各样任务,支持着我们日常的桌面操作。有时候可能需要服务与用户进行信息或界面交互操作,这种方式在XP 时代是没有问题的,但自从Vista 开始你会发现这种方式似乎已不起作用。

现在有个需求需要服务程序弹框提示和启动包含复杂UI的桌面程序,"穿透Session 0 隔离"这篇文章已经写得很好了,看了之后非常有帮助,但是在最后启动了cmd之后发现就只能启动cmd,启动其他类型的程序都会报错。仔细看了评论发现还是没有解决,只是照着抄了一遍,发现不仔细看还是不是自己的东西(知识)啊。

原文链接:

穿透Session 0 隔离(一)

穿透Session 0 隔离(二)

最后修改了一下程序,解决了问题。跟原博主李敬然写的稍微有点区别。我的是抄的msdn的代码。总之就是 CreateProcessAsUser 函数的申明和调用有些区别。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.InteropServices;using System.Security.Principal;namespace WindowsService1 public class WinAPI_Interop public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; /// summary  /// 服务程序执行消息提示,前台MessageBox.Show /// /summary  /// param  消息内容 /param  /// param  标题 /param  public static void ShowServiceMessage(string message, string title) int resp = 0; WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, 0, 0, out resp, false); [DllImport("kernel32.dll", SetLastError = true)] public static extern int WTSGetActiveConsoleSessionId(); [DllImport("wtsapi32.dll", SetLastError = true)] public static extern bool WTSSendMessage(IntPtr hServer, int SessionId, String pTitle, int TitleLength, String pMessage, int MessageLength,int Style, int Timeout, out int pResponse, bool bWait); #region P/Invoke WTS APIs private enum WTS_CONNECTSTATE_CLASS WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct WTS_SESSION_INFO public UInt32 SessionID; public string pWinStationName; public WTS_CONNECTSTATE_CLASS State; [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool WTSEnumerateSessions( IntPtr hServer, [MarshalAs(UnmanagedType.U4)] UInt32 Reserved, [MarshalAs(UnmanagedType.U4)] UInt32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern void WTSFreeMemory(IntPtr pMemory); [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token); #endregion #region P/Invoke CreateProcessAsUser /// summary  /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser.  /// /summary  ///  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct STARTUPINFO public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct PROCESS_INFORMATION public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; /// summary  /// 以当前登录的windows用户(角色权限)运行指定程序进程 /// /summary  /// param  /param  /// param  指定程序(全路径) /param  /// param  参数 /param  /// param  进程属性 /param  /// param  线程属性 /param  /// param  /param  /// param  /param  /// param  /param  /// param  /param  /// param  程序启动属性 /param  /// param  最后返回的进程信息 /param  /// returns 是否调用成功 /returns  [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool CreateProcessAsUser(IntPtr hToken,string lpApplicationName,string lpCommandLine,IntPtr lpProcessAttributes,IntPtr lpThreadAttributes, bool bInheritHandles,uint dwCreationFlags,string lpEnvironment,string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,out PROCESS_INFORMATION lpProcessInformation); [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool CloseHandle(IntPtr hHandle); #endregion /// summary  /// 以当前登录系统的用户角色权限启动指定的进程 /// /summary  /// param  指定的进程(全路径) /param  public static void CreateProcess(string ChildProcName) IntPtr ppSessionInfo = IntPtr.Zero; UInt32 SessionCount = 0; if (WTSEnumerateSessions( (IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero.  0, // This reserved parameter must be zero.  1, // The version of the enumeration request must be 1.  ref ppSessionInfo, // This would point to an array of session info.  ref SessionCount // This would indicate the length of the above array. for (int nCount = 0; nCount SessionCount; nCount++) WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO)); if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State) IntPtr hToken = IntPtr.Zero; if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken)) PROCESS_INFORMATION tProcessInfo; STARTUPINFO tStartUpInfo = new STARTUPINFO(); tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO)); bool ChildProcStarted = CreateProcessAsUser( hToken, // Token of the logged-on user.  ChildProcName, // Name of the process to be started.  null, // Any command line arguments to be passed.  IntPtr.Zero, // Default Process' attributes.  IntPtr.Zero, // Default Thread's attributes.  false, // Does NOT inherit parent's handles.  0, // No any specific creation flag.  null, // Default environment path.  null, // Default current directory.  ref tStartUpInfo, // Process Startup Info.  out tProcessInfo // Process information to be returned.  if (ChildProcStarted) CloseHandle(tProcessInfo.hThread); CloseHandle(tProcessInfo.hProcess); else ShowServiceMessage("CreateProcessAsUser失败", "CreateProcess"); CloseHandle(hToken); break; WTSFreeMemory(ppSessionInfo);}

调用:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Diagnostics;using System.Linq;using System.ServiceProcess;using System.Text;using System.Windows.Forms;namespace WindowsService1 public partial class AlertService : ServiceBase public AlertService() InitializeComponent(); protected override void OnStart(string[] args) //Interop.ShowMessageBox("This a message from AlertService.","AlertService Message"); WinAPI_Interop.CreateProcess(@"E:workoxGreenlandBoxBinFilesClientBinBufferBox.exe"); //Interop.CreateProcess("cmd.exe", @"C:WindowsSystem32"); protected override void OnStop()}