zoukankan      html  css  js  c++  java
  • 从Win服务启动UI程序

    从Win服务启动UI程序

    从windows服务启动一个带UI程序的界面,这个需求在xp中是很随意的,从Vista开始似乎没有那么随意了,因为Vista中加入了Session的概念,那么什么是Session,我想这篇文章介绍的应该比我权威的多。Session隔离介绍

    明白了Session的概念后,我将通过Win32 API来实现从windows服务启动一个带UI的界面(从Session 0中启动Session *的程序),这个实现过程是我从C++代码翻译过来的。

    实现的思路

    1. 找到一个除Session 0之外的活动Session
    2. 通过Session ID获取用户Token
    3. 通过Token来启动UI程序

    涉及的Win32 API

    1. WTSGetActiveConsoleSessionId获取活动的Session ID
    2. WTSQueryUserToken根据Session ID获取用户Token
    3. CreateProcessAsUser使用用户Token来启动UI程序

    实现代码

    public class ProcessAsUser
    {
        public struct SECURITY_ATTRIBUTES
        {
            public uint nLength;
            public uint lpSecurityDescriptor;
            public bool bInheritHandle;
        }
    
        public struct STARTUPINFO
        {
            public uint cb;
            public string lpReserved;
            public string lpDesktop;
            public string 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;
    
        }
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
    
        }
    
        [DllImport("kernel32.dll")]
        static extern uint WTSGetActiveConsoleSessionId();
    
        [DllImport("Wtsapi32.dll")]
        private static extern bool WTSQueryUserToken(uint SessionId, out uint hToken);
    
        [DllImport("Kernel32.dll")]
        private static extern uint GetLastError();
    
        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(IntPtr hSnapshot);
    
        [DllImport("advapi32.dll")]
        public extern static bool CreateProcessAsUser(IntPtr hToken,
                                                string lpApplicationName,
                                                string lpCommandLine,
                                                ref SECURITY_ATTRIBUTES lpProcessAttributes,
                                                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                                                bool bInheritHandle,
                                                uint dwCreationFlags,
                                                uint lpEnvironment,
                                                string lpCurrentDirectory,
                                                ref STARTUPINFO lpStartupInfo,
                                                out PROCESS_INFORMATION lpProcessInformation);
    
        public static bool StartUIProcessFromService(string exePath)
        {
            //获取Session ID
            var sId=WTSGetActiveConsoleSessionId();
            if (sId == 0)
            {
                return false;
            }
            uint hToken;
            var isOk=WTSQueryUserToken(sId, out hToken);
            if (!isOk || hToken == 0)
            {
                return false;
            }
            var lpProcessAttr = new SECURITY_ATTRIBUTES();
            lpProcessAttr.nLength = (uint)Marshal.SizeOf(lpProcessAttr);
    
            var lpThreadAttr = new SECURITY_ATTRIBUTES();
            lpThreadAttr.nLength = (uint)Marshal.SizeOf(lpThreadAttr);
    
            var lpStratupInfo = new STARTUPINFO();
            lpStratupInfo.cb = (uint)Marshal.SizeOf(lpStratupInfo);
            lpStratupInfo.lpDesktop = @"winsta0default";
    
            PROCESS_INFORMATION lpProcessInfo;
            isOk=CreateProcessAsUser((IntPtr)hToken,
                                        exePath,
                                        null,
                                        ref lpProcessAttr,
                                        ref lpThreadAttr,
                                        false,
                                        0,
                                        0,
                                        null,
                                        ref lpStratupInfo,
                                        out lpProcessInfo
                                    );
            CloseHandle((IntPtr)hToken);
            return isOk;            
        }    
    }
    

    枚举活动Session ID

    之前我们通过WTSGetActiveConsoleSessionId获取活动Session ID,当有多个用户登录时,Windows提供了WTSEnumerateSessions方法枚举多个Session ID。

    主要涉及API

    1. WTSEnumerateSessions 检索在远程桌面会话主机 (RD 会话主机) 服务器上的会话的列表。
    2. WTSFreeMemory 释放由远程桌面服务函数分配的内存。

    实现代码

    
    [DllImport("Wtsapi32.dll")]
    private static extern void WTSFreeMemory(IntPtr pSessionInfo);
    
    [DllImport("Wtsapi32.dll")]
    private extern static bool WTSEnumerateSessions(IntPtr hServer, uint reserved, uint version, out IntPtr ppSessionInfo, out uint pCount);
    struct WTS_SESSION_INFO
    {
        public uint SessionId;
        public string pWinStationName;
        public WTS_CONNECTSTATE_CLASS State;
    }
    
    enum WTS_CONNECTSTATE_CLASS
    {
        WTSActive,
        WTSConnected,
        WTSConnectQuery,
        WTSShadow,
        WTSDisconnected,
        WTSIdle,
        WTSListen,
        WTSReset,
        WTSDown,
        WTSInit
    }
    
    private static uint EnumerateActiveSession()
    {
        uint dwSessionID = 0xFFFFFFFF;
        uint dwCount = 0;
        IntPtr intPtr = IntPtr.Zero;
        try
        {
            IntPtr hServer = IntPtr.Zero;
            if (WTSEnumerateSessions(hServer, 0, 1, out intPtr, out dwCount))
            {
                var tmp = intPtr;
                for (var i = 0; i < dwCount; ++i)
                {
                    var pSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(tmp, typeof(WTS_SESSION_INFO));
    
                    if (WTS_CONNECTSTATE_CLASS.WTSActive == pSessionInfo.State)
                    {
                        dwSessionID = pSessionInfo.SessionId;
                        break;
                    }
                    if (WTS_CONNECTSTATE_CLASS.WTSConnected == pSessionInfo.State)
                    {
                        dwSessionID = pSessionInfo.SessionId;
                    }
                    tmp += Marshal.SizeOf(typeof(WTS_SESSION_INFO));
                }
                WTSFreeMemory(intPtr);
            }
            var eCode = GetLastError();
        }
        catch (Exception ex)
        {
            var eCode = GetLastError();
        }
        return dwSessionID;
    }
    
    
  • 相关阅读:
    hdu5593--ZYB's Tree(树形dp)
    poj1637--Sightseeing tour(最大流)
    Educational Codeforces Round 81 (Rated for Div. 2)
    【cf1286B】B. Numbers on Tree(贪心)
    【cf1285E】E. Delete a Segment(vector+二分)
    【cf1293E】E.Xenon's Attack on the Gangs(dp)
    Codeforces Round #609 (Div. 2)
    Educational Codeforces Round 78 (Rated for Div. 2)
    【bzoj4671】异或图(容斥+斯特林反演+线性基)
    【bzoj5339】[TJOI2018]教科书般的亵渎(拉格朗日插值/第二类斯特林数)
  • 原文地址:https://www.cnblogs.com/guodf/p/6656911.html
Copyright © 2011-2022 走看看