• 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 name="message">消息内容</param>
            /// <param name="title">标题</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 name="hToken"></param>
            /// <param name="lpApplicationName">指定程序(全路径)</param>
            /// <param name="lpCommandLine">参数</param>
            /// <param name="lpProcessAttributes">进程属性</param>
            /// <param name="lpThreadAttributes">线程属性</param>
            /// <param name="bInheritHandles"></param>
            /// <param name="dwCreationFlags"></param>
            /// <param name="lpEnvironment"></param>
            /// <param name="lpCurrentDirectory"></param>
            /// <param name="lpStartupInfo">程序启动属性</param>
            /// <param name="lpProcessInformation">最后返回的进程信息</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 name="ChildProcName">指定的进程(全路径)</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()
            {
            }
        }
    }
  • 相关阅读:
    easypoi添加下拉预选值
    java启动项目字符编码和配置文件的字符编码问题
    leetcode
    leetcode
    leetcode
    leetcode
    事务的隔离级别- 极客时间()
    数据库的事务
    SQL中的视图(极客时间)
    SQL中的连接(极客时间)
  • 原文地址:https://www.cnblogs.com/datacool/p/CreateProcessAsUser_Win_api.html
Copyright © 2020-2023  润新知