时间:2021-07-01 10:21:17 帮助过:34人阅读
- <br>public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; <br><br>public static void ShowMessageBox(string message, string title) <br>{ <br>int resp = 0; <br>WTSSendMessage( <br>WTS_CURRENT_SERVER_HANDLE, <br>WTSGetActiveConsoleSessionId(), <br>title, title.Length, <br>message, message.Length, <br>0, 0, out resp, false); <br>} <br><br>[DllImport("kernel32.dll", SetLastError = true)] <br>public static extern int WTSGetActiveConsoleSessionId(); <br><br>[DllImport("wtsapi32.dll", SetLastError = true)] <br>public static extern bool WTSSendMessage( <br>IntPtr hServer, <br>int SessionId, <br>String pTitle, <br>int TitleLength, <br>String pMessage, <br>int MessageLength, <br>int Style, <br>int Timeout, <br>out int pResponse, <br>bool bWait); <br> <br>在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>protected override void OnStart(string[] args) <br>{ <br>Interop.ShowMessageBox("This a message from AlertService.", "AlertService Message"); <br>} <br> <br>编译程序后在服务管理器中重新启动AlertService 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是Session 0 中。 <br></li><li><p><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title="" border="0" alt="" src="https://img.gxlcms.com//Uploads-s/new/2019-09-19-201919/2012111015060013.png" width="547" height="314"> </p>CreateProcessAsUser 函数 </li><li><p> 如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。打开Interop 类继续添加下面代码:<br><br><span><u></u></span> 代码如下:</p><pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>public static void CreateProcess(string app, string path) <br>{ <br>bool result; <br>IntPtr hToken = WindowsIdentity.GetCurrent().Token; <br>IntPtr hDupedToken = IntPtr.Zero; <br><br>PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); <br>SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); <br>sa.Length = Marshal.SizeOf(sa); <br><br>STARTUPINFO si = new STARTUPINFO(); <br>si.cb = Marshal.SizeOf(si); <br><br>int dwSessionID = WTSGetActiveConsoleSessionId(); <br>result = WTSQueryUserToken(dwSessionID, out hToken); <br><br>if (!result) <br>{ <br>ShowMessageBox("WTSQueryUserToken failed", "AlertService Message"); <br>} <br><br>result = DuplicateTokenEx( <br>hToken, <br>GENERIC_ALL_ACCESS, <br>ref sa, <br>(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, <br>(int)TOKEN_TYPE.TokenPrimary, <br>ref hDupedToken <br>); <br><br>if (!result) <br>{ <br>ShowMessageBox("DuplicateTokenEx failed" ,"AlertService Message"); <br>} <br><br>IntPtr lpEnvironment = IntPtr.Zero; <br>result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false); <br><br>if (!result) <br>{ <br>ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message"); <br>} <br><br>result = CreateProcessAsUser( <br>hDupedToken, <br>app, <br>String.Empty, <br>ref sa, ref sa, <br>false, 0, IntPtr.Zero, <br>path, ref si, ref pi); <br><br>if (!result) <br>{ <br>int error = Marshal.GetLastWin32Error(); <br>string message = String.Format("CreateProcessAsUser Error: {0}", error); <br>ShowMessageBox(message, "AlertService Message"); <br>} <br><br>if (pi.hProcess != IntPtr.Zero) <br>CloseHandle(pi.hProcess); <br>if (pi.hThread != IntPtr.Zero) <br>CloseHandle(pi.hThread); <br>if (hDupedToken != IntPtr.Zero) <br>CloseHandle(hDupedToken); <br>} <br><br>[StructLayout(LayoutKind.Sequential)] <br>public struct STARTUPINFO <br>{ <br>public Int32 cb; <br>public string lpReserved; <br>public string lpDesktop; <br>public string lpTitle; <br>public Int32 dwX; <br>public Int32 dwY; <br>public Int32 dwXSize; <br>public Int32 dwXCountChars; <br>public Int32 dwYCountChars; <br>public Int32 dwFillAttribute; <br>public Int32 dwFlags; <br>public Int16 wShowWindow; <br>public Int16 cbReserved2; <br>public IntPtr lpReserved2; <br>public IntPtr hStdInput; <br>public IntPtr hStdOutput; <br>public IntPtr hStdError; <br>} <br><br>[StructLayout(LayoutKind.Sequential)] <br>public struct PROCESS_INFORMATION <br>{ <br>public IntPtr hProcess; <br>public IntPtr hThread; <br>public Int32 dwProcessID; <br>public Int32 dwThreadID; <br>} <br><br>[StructLayout(LayoutKind.Sequential)] <br>public struct SECURITY_ATTRIBUTES <br>{ <br>public Int32 Length; <br>public IntPtr lpSecurityDescriptor; <br>public bool bInheritHandle; <br>} <br><br>public enum SECURITY_IMPERSONATION_LEVEL <br>{ <br>SecurityAnonymous, <br>SecurityIdentification, <br>SecurityImpersonation, <br>SecurityDelegation <br>} <br><br>public enum TOKEN_TYPE <br>{ <br>TokenPrimary = 1, <br>TokenImpersonation <br>} <br><br>public const int GENERIC_ALL_ACCESS = 0x10000000; <br><br>[DllImport("kernel32.dll", SetLastError = true, <br>CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] <br>public static extern bool CloseHandle(IntPtr handle); <br><br>[DllImport("advapi32.dll", SetLastError = true, <br>CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] <br>public static extern bool CreateProcessAsUser( <br>IntPtr hToken, <br>string lpApplicationName, <br>string lpCommandLine, <br>ref SECURITY_ATTRIBUTES lpProcessAttributes, <br>ref SECURITY_ATTRIBUTES lpThreadAttributes, <br>bool bInheritHandle, <br>Int32 dwCreationFlags, <br>IntPtr lpEnvrionment, <br>string lpCurrentDirectory, <br>ref STARTUPINFO lpStartupInfo, <br>ref PROCESS_INFORMATION lpProcessInformation); <br><br>[DllImport("advapi32.dll", SetLastError = true)] <br>public static extern bool DuplicateTokenEx( <br>IntPtr hExistingToken, <br>Int32 dwDesiredAccess, <br>ref SECURITY_ATTRIBUTES lpThreadAttributes, <br>Int32 ImpersonationLevel, <br>Int32 dwTokenType, <br>ref IntPtr phNewToken); <br><br>[DllImport("wtsapi32.dll", SetLastError=true)] <br>public static extern bool WTSQueryUserToken( <br>Int32 sessionId, <br>out IntPtr Token); <br><br>[DllImport("userenv.dll", SetLastError = true)] <br>static extern bool CreateEnvironmentBlock( <br>out IntPtr lpEnvironment, <br>IntPtr hToken, <br>bool bInherit); <br> <br>在CreateProcess 函数中同时也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函数的使用,有兴趣的朋友可通过MSDN 进行学习。完成CreateProcess 函数创建后,就可以真正的通过它来调用应用程序了,回到Service1.cs 修改一下OnStart 我们来打开一个CMD 窗口。如下代码: <br><span><u></u></span> 代码如下:<pre class="brush:php;toolbar:false layui-box layui-code-view layui-code-notepad"><ol class="layui-code-ol"><li><br>protected override void OnStart(string[] args) <br>{ <br>Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\"); <br>} <br> <br>重新编译程序,启动AlertService 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对Session 0 隔离问题进行解决。大家也可以通过WCF 等技术完成一些更复杂的跨Session 通信方式,实现在Windows 7 及Vista 系统中服务与桌面用户的交互操作。 <p></p></li><li><p><img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title="" border="0" alt="" src="https://img.gxlcms.com//Uploads-s/new/2019-09-19-201919/2012111015060014.png" width="627" height="397"> </p></li><li><p>参考资料 <br><br>1. WTSSendMessage Function <br>http://msdn.microsoft.com/en-us/library/aa383842(VS.85).aspx</p></li><li><p>2. CreateProcessAsUser Function <br>http://msdn.microsoft.com/en-us/library/ms682429(v=VS.85).aspx</p></li><li><p>3. WTSSendMessage (wtsapi32) <br>http://www.pinvoke.net/default.aspx/wtsapi32/WTSSendMessage.html</p></li><li><p>4. WTSQueryUserToken Function <br>http://msdn.microsoft.com/en-us/library/aa383840(VS.85).aspx</p></li><li><p>5. http://www.pinvoke.net/</p></li><li><p>代码下载 AlertService2_jb51.rar<br><br>作者:李敬然(Gnie) <br>出处:{GnieTech} (http://www.cnblogs.com/gnielee/)</p></li><li> </li><li> </li></ol></pre></li></ol></pre></li></ol></pre>