UAC环境下,从服务启动用户界面程序

之前从服务启动用户界面程序,使用的都是CreateProcess,或者.net库里面的Process::Start函数。但是在WIN2008上面碰到了问题,进程能启动,但是界面出不来。

原因是微软搞得UAC技术。

UAC(User Account Control,用户账户控制) 是微软为提高系统安全而在Windows Vista中引入的新技术,通过限制应用软件而改进Windows操作系统的安全性。

 

具体到我的程序上,就是无法从服务直接创建窗口。

实际上,用户窗口还是被创建出来了。但是由于服务是用system用户运行的,有自己的窗口站,和我们默认使用的winsta0不是一个窗口站,不能直接通讯,交互,所以当然不能在 "winsta0" 中的默认桌面上显示了。

虽然在VISTA里面就有了,但以前在项目中碰不到。因为用户很少用Vista或者Win7,服务端也都是WIN2003。现在WIN2008用的多了,问题就出来了。

 

在网上搜了半天,找到了解决方案:

服务启动UI程序不能直接CreateProcess(),否则因为service session,程序UI不能看见
拿到当前explorer.exe的token,然后CreateProcessAsUser模拟当前用户启动进程...这样就可以显示界面了

代码如下:

bool GetTokenByName(ref IntPtr hToken, string lpName)
{
    IntPtr hProcessSnap = IntPtr.Zero;
    bool bRet = false;

    hProcessSnap = CreateToolhelp32Snapshot(0x00000002, 0);
    if ((int)hProcessSnap <= 0)
    {
        return false;
    }

    //--------------------------------------------
    //
    ProcessEntry32 pe32 = new ProcessEntry32();
    pe32.dwSize = (uint)Marshal.SizeOf(pe32);
    int bMore = Process32First(hProcessSnap, ref pe32);
    while (bMore == 1)
    {
        if (0 == string.Compare(pe32.szExeFile, lpName, true))
        {
            int hProcess = OpenProcess(0x0400, false, (int)pe32.th32ProcessID);
            System.IntPtr p = new IntPtr(hProcess);
            bRet = OpenProcessToken(p, (int)TOKEN_ALL_ACCESS, ref hToken);

            CloseHandle(hProcessSnap);

            return bRet;
        }
        bMore = Process32Next(hProcessSnap, ref pe32);
    }
    CloseHandle(hProcessSnap);

    return false;
}

public bool RunProcess(string szExe, string szPath)
{
    IntPtr hToken = new IntPtr();
    if (!GetTokenByName(ref hToken, "explorer.exe"))
    {
        return false;
    }
    STARTUPINFO si = new STARTUPINFO();
    si.cb = Marshal.SizeOf(si);

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

    bool result = CreateProcessAsUser(
                                 hToken,
                                 szExe,
                                 String.Empty,
                                 ref sa, ref sa,
                                 false, 0, IntPtr.Zero,
                                 szPath, ref si, ref pi);

    return result;
}

[DllImport("KERNEL32.DLL ")]
public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processid);
[DllImport("KERNEL32.DLL ")]
public static extern int CloseHandle(IntPtr handle);
[DllImport("KERNEL32.DLL ")]
public static extern int Process32First(IntPtr handle, ref   ProcessEntry32 pe);
[DllImport("KERNEL32.DLL ")]
public static extern int Process32Next(IntPtr handle, ref   ProcessEntry32 pe);

[StructLayout(LayoutKind.Sequential)]
public struct ProcessEntry32
{
    public uint dwSize;
    public uint cntUsage;
    public uint th32ProcessID;
    public IntPtr th32DefaultHeapID;
    public uint th32ModuleID;
    public uint cntThreads;
    public uint th32ParentProcessID;
    public int pcPriClassBase;
    public uint dwFlags;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szExeFile;
};

[DllImport("kernel32.dll")]
public static extern int OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

private const int TOKEN_ASSIGN_PRIMARY = 0x1;
private const int TOKEN_DUPLICATE = 0x2;
private const int TOKEN_IMPERSONATE = 0x4;
private const int TOKEN_QUERY = 0x8;
private const int TOKEN_QUERY_SOURCE = 0x10;
private const int TOKEN_ADJUST_PRIVILEGES = 0x20;
private const int TOKEN_ADJUST_GROUPS = 0x40;
private const int TOKEN_ADJUST_DEFAULT = 0x80;
private const int TOKEN_ALL_ACCESS = TOKEN_ASSIGN_PRIMARY
      + TOKEN_DUPLICATE + TOKEN_IMPERSONATE + TOKEN_QUERY
      + TOKEN_QUERY_SOURCE + TOKEN_ADJUST_PRIVILEGES
      + TOKEN_ADJUST_GROUPS + TOKEN_ADJUST_DEFAULT;
private const int ANYSIZE_ARRAY = 1;
[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
}

[DllImport("kernel32.dll", SetLastError = true,
    CharSet = CharSet.Auto, 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);

posted @ 2013-04-18 13:57  maksheiev  阅读(982)  评论(0编辑  收藏  举报