• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    asp.net中穿透Session 0 隔离(二)
    对于简单的交互,服务可以通过WTSSendMessage 函数,在用户Session 上显示消息窗口。对于一些复杂的UI 交互,必须调用CreateProcessAsUser 或其他方法(WCF、.NET远程处理等)进行跨Session 通信,在桌面用户上创建一个应用程序界面。

    WTSSendMessage 函数
    如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现。首先,在上一篇下载的代码中加入一个Interop.cs 类,并在类中加入如下代码:

    复制代码 代码如下:

    public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

    public static void ShowMessageBox(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);

    在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码:
    复制代码 代码如下:

    protected override void OnStart(string[] args)
    {
    Interop.ShowMessageBox("This a message from AlertService.", "AlertService Message");
    }

    编译程序后在服务管理器中重新启动AlertService 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是Session 0 中。

    CreateProcessAsUser 函数

         如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。打开Interop 类继续添加下面代码:

    复制代码 代码如下:

    public static void CreateProcess(string app, string path)
    {
    bool result;
    IntPtr hToken = WindowsIdentity.GetCurrent().Token;
    IntPtr hDupedToken = IntPtr.Zero;

    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
    sa.Length = Marshal.SizeOf(sa);

    STARTUPINFO si = new STARTUPINFO();
    si.cb = Marshal.SizeOf(si);

    int dwSessionID = WTSGetActiveConsoleSessionId();
    result = WTSQueryUserToken(dwSessionID, out hToken);

    if (!result)
    {
    ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
    }

    result = DuplicateTokenEx(
    hToken,
    GENERIC_ALL_ACCESS,
    ref sa,
    (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
    (int)TOKEN_TYPE.TokenPrimary,
    ref hDupedToken
    );

    if (!result)
    {
    ShowMessageBox("DuplicateTokenEx failed" ,"AlertService Message");
    }

    IntPtr lpEnvironment = IntPtr.Zero;
    result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);

    if (!result)
    {
    ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
    }

    result = CreateProcessAsUser(
    hDupedToken,
    app,
    String.Empty,
    ref sa, ref sa,
    false, 0, IntPtr.Zero,
    path, ref si, ref pi);

    if (!result)
    {
    int error = Marshal.GetLastWin32Error();
    string message = String.Format("CreateProcessAsUser Error: {0}", error);
    ShowMessageBox(message, "AlertService Message");
    }

    if (pi.hProcess != IntPtr.Zero)
    CloseHandle(pi.hProcess);
    if (pi.hThread != IntPtr.Zero)
    CloseHandle(pi.hThread);
    if (hDupedToken != IntPtr.Zero)
    CloseHandle(hDupedToken);
    }

    [StructLayout(LayoutKind.Sequential)]
    public 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 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)]
    public struct PROCESS_INFORMATION
    {
    public IntPtr hProcess;
    public IntPtr hThread;
    public Int32 dwProcessID;
    public Int32 dwThreadID;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
    public Int32 Length;
    public IntPtr lpSecurityDescriptor;
    public bool bInheritHandle;
    }

    public enum SECURITY_IMPERSONATION_LEVEL
    {
    SecurityAnonymous,
    SecurityIdentification,
    SecurityImpersonation,
    SecurityDelegation
    }

    public enum TOKEN_TYPE
    {
    TokenPrimary = 1,
    TokenImpersonation
    }

    public const int GENERIC_ALL_ACCESS = 0x10000000;

    [DllImport("kernel32.dll", SetLastError = true,
    CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", SetLastError = true,
    CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern bool CreateProcessAsUser(
    IntPtr hToken,
    string lpApplicationName,
    string lpCommandLine,
    ref SECURITY_ATTRIBUTES lpProcessAttributes,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandle,
    Int32 dwCreationFlags,
    IntPtr lpEnvrionment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    ref PROCESS_INFORMATION lpProcessInformation);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool DuplicateTokenEx(
    IntPtr hExistingToken,
    Int32 dwDesiredAccess,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    Int32 ImpersonationLevel,
    Int32 dwTokenType,
    ref IntPtr phNewToken);

    [DllImport("wtsapi32.dll", SetLastError=true)]
    public static extern bool WTSQueryUserToken(
    Int32 sessionId,
    out IntPtr Token);

    [DllImport("userenv.dll", SetLastError = true)]
    static extern bool CreateEnvironmentBlock(
    out IntPtr lpEnvironment,
    IntPtr hToken,
    bool bInherit);

    在CreateProcess 函数中同时也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函数的使用,有兴趣的朋友可通过MSDN 进行学习。完成CreateProcess 函数创建后,就可以真正的通过它来调用应用程序了,回到Service1.cs 修改一下OnStart 我们来打开一个CMD 窗口。如下代码:
    复制代码 代码如下:

    protected override void OnStart(string[] args)
    {
    Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\");
    }

    重新编译程序,启动AlertService 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对Session 0 隔离问题进行解决。大家也可以通过WCF 等技术完成一些更复杂的跨Session 通信方式,实现在Windows 7 及Vista 系统中服务与桌面用户的交互操作。

    参考资料

    1. WTSSendMessage Function
    http://msdn.microsoft.com/en-us/library/aa383842(VS.85).aspx

    2. CreateProcessAsUser Function
    http://msdn.microsoft.com/en-us/library/ms682429(v=VS.85).aspx

    3. WTSSendMessage (wtsapi32)
    http://www.pinvoke.net/default.aspx/wtsapi32/WTSSendMessage.html

    4. WTSQueryUserToken Function
    http://msdn.microsoft.com/en-us/library/aa383840(VS.85).aspx

    5. http://www.pinvoke.net/

    代码下载 AlertService2_jb51.rar

    作者:李敬然(Gnie)
    出处:{GnieTech} (http://www.cnblogs.com/gnielee/)

    您可能感兴趣的文章:
    • asp.net中穿透Session 0 隔离(一)
    上一篇:asp.net中穿透Session 0 隔离(一)
    下一篇:ASP.NET MVC:Filter和Action的执行介绍
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    asp.net中穿透Session 0 隔离(二) asp.net,中,穿透,Session,隔离,