如果要用服务来启动一个带窗口的程序,你会发现只有进程在,但没有窗口出现。
可以写一个Process.run记事体来测试,看有没有记事本窗口。
出现这问题的原因是服务是以system帐号启动的,但当前widnows的启动者是用户身份的administrator或者其它用户自建的管理员帐号, 不在同个会话上当然没有窗体,国外一个大神写了一个类解决了这个问题,获取当前登录的用户sessionId,并用它来启动程序,这样就有窗口了,感谢这位大神,直接上代码:


 public class LoaderMan
    {
        public const int MAXIMUM_ALLOWED = 0x2000000;
       // public const IntPtr INVALID_HANDLE_VALUE = 0xffffffff;

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hSnapshot);
        //sessionId是用户的会话ID,默认为当前活动用户;appFullName是程序完整路径,args是启动参数
        public static int CreateProcess(int sessionId, string appFullName, string args)
        {
            if (!System.IO.File.Exists(appFullName))
            {
                throw new System.IO.FileNotFoundException(appFullName);
            }
            bool sucess = false;
            IntPtr hToken = IntPtr.Zero,
                   hDupedToken = IntPtr.Zero,
                   lpEnvironment = IntPtr.Zero;
            Process_Information pi = new Process_Information();
            SecurityAttributes sa;
            try
            {
                //获取指定会话的用户令牌,须具备System权限
                sucess = WTSQueryUserToken(sessionId, out hToken);
                if (!sucess)
                {
                    //服务程序中,获取指定会话的桌面进程
                    var explorer = Process.GetProcesses()
                        .FirstOrDefault(p => p.SessionId == sessionId && string.Equals(p.ProcessName, "explorer", StringComparison.OrdinalIgnoreCase));
                    if (explorer == null)
                    {
                        return 0;
                    }
                    sucess = OpenProcessToken(explorer.Handle, TokenAccessLevels.AllAccess, ref hToken);
                    if (!sucess)
                    {
                        //TraceWin32Error("CreateProcessAs Session" + sessionId.ToString(), "WTSQueryUserToken");
                        return 0;
                    }
                }
                //复制桌面进程的句柄
                sa = new SecurityAttributes();
                sa.Length = Marshal.SizeOf(sa);
                var si = new StartUpInfo();
                si.cb = Marshal.SizeOf(si);
                sucess =DuplicateTokenEx(
                      hToken,
                     MAXIMUM_ALLOWED,
                      ref sa,
                      (int)SecurityImpersonationLevel.SecurityIdentification,
                      (int)TokenType.TokenPrimary,
                      ref hDupedToken
                );
                if (!sucess)
                {
                    //TraceWin32Error("CreateProcessAs Session" + sessionId.ToString(), "DuplicateTokenEx");
                    return 0;
                }
                //利用复制的句柄在指定的会话中初始化运行环境                
                sucess =CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
                if (!sucess)
                {
                    //TraceWin32Error("CreateProcessAs Session" + sessionId.ToString(), "CreateEnvironmentBlock");
                    return 0;
                }
                //在指定会话中开启进程
                if (!string.IsNullOrEmpty(args))
                {
                    args = string.Format("\"{0}\" {1}", appFullName, args);
                    appFullName = null;
                }
                sucess =CreateProcessAsUser(
                    hDupedToken,
                    appFullName,
                    args,
                    ref sa, ref sa,
                    false, 0, IntPtr.Zero,
                    null,
                    ref si,
                    ref pi
                );
               
                if (!sucess)
                {
                    //TraceWin32Error("CreateProcessAs Session" + sessionId.ToString(), "CreateProcessAsUser");
                }
                return pi.dwProcessID;
            }
            catch (Exception exp)
            {
                //TraceWin32Error("CreateProcessAs Session" + sessionId.ToString(), exp.Message);
                return 0;
            }
            finally
            {
                if (hDupedToken != IntPtr.Zero)CloseHandle(hDupedToken);
                if (lpEnvironment != IntPtr.Zero)DestroyEnvironmentBlock(lpEnvironment);
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
        }

        public static int? GetActiveSessionId()
        {
            IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero, ppSessionInfo = IntPtr.Zero;
            List<string> result = new List<string>();
            try
            {
                int count = 0;
                bool success =WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count);
                if (success)
                {
                    int dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
                    var current = ppSessionInfo.ToInt64();  //数组起始地址
                    for (int i = 0; i < count; i++)
                    {
                        var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
                        if (si.State ==WTS_CONNECTSTATE_CLASS.WTSActive)
                        {
                            return si.SessionID;
                        }
                        current += dataSize;
                    }
                }
                else
                {
                    //TraceWin32Error("GetActiveSessionId", "WTSEnumerateSessions");
                }
                return null;
            }
            finally
            {
                if (ppSessionInfo != IntPtr.Zero)WTSFreeMemory(ppSessionInfo);
                //CloseHandle(ppSessionInfo);
            }
        }

        #region API声明
        [DllImport("wtsapi32.dll", SetLastError = true)]
        public static extern bool WTSEnumerateSessions(
                    IntPtr hServer,
                    [MarshalAs(UnmanagedType.U4)] uint Reserved,
                    [MarshalAs(UnmanagedType.U4)] uint Version,
                    ref IntPtr ppSessionInfo,
                    [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);
        /// <summary> 
        /// Terminal Services API Functions,The WTSFreeMemory function frees memory allocated by a Terminal Services function. 
        /// </summary> 
        /// <param name="pMemory">[in] Pointer to the memory to free</param> 
        [DllImport("wtsapi32.dll")]
        public static extern void WTSFreeMemory(System.IntPtr pMemory);

        [StructLayout(LayoutKind.Sequential)]
        public struct WTS_SESSION_INFO
        {
            public Int32 SessionID;

            [MarshalAs(UnmanagedType.LPStr)]
            public String pWinStationName;

            public WTS_CONNECTSTATE_CLASS State;
        }

        public enum WTS_CONNECTSTATE_CLASS
        {
            WTSActive,
            WTSConnected,
            WTSConnectQuery,
            WTSShadow,
            WTSDisconnected,
            WTSIdle,
            WTSListen,
            WTSReset,
            WTSDown,
            WTSInit
        }

        [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 SecurityAttributes
        {
            public Int32 Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }

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

        public enum TokenType
        {
            TokenPrimary = 1,
            TokenImpersonation
        }

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

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

        [DllImport("userenv.dll", SetLastError = true)]
        public static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);

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

        //以下定义同System.Windows.Forms.SecurityIDType
        public enum SID_NAME_USE
        {
            User = 1,
            Group,
            Domain,
            Alias,
            WellKnownGroup,
            Account,
            Invalid,
            Unknown,
            Computer,
            Label
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_USER
        {
            public SID_AND_ATTRIBUTES User;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SID_AND_ATTRIBUTES
        {
            public IntPtr Sid;
            public uint Attributes;
        }

        /// <summary>
        /// 获取控制台当前活动的会话ID,若没有将返回0xFFFFFFFF(在远程连接至Server2008或Win8时取得的值并不是用户的会话ID)
        /// </summary>
        /// <returns></returns>
        //[DllImport("kernel32.dll", SetLastError = true)]
        //public static extern uint WTSGetActiveConsoleSessionId();

        /// <summary>
        /// 查询指定会话ID的用户令牌,调用方必须具备System权限
        /// </summary>
        [DllImport("wtsapi32.dll", SetLastError = true)]
        public static extern bool WTSQueryUserToken(int sessionId, out IntPtr Token);

        [DllImport("advapi32", SetLastError = true)]
        public static extern bool OpenProcessToken(IntPtr processHandle, System.Security.Principal.TokenAccessLevels desiredAccess, ref IntPtr htok);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool GetTokenInformation(IntPtr htok, uint tokenInformationClass, IntPtr hTokInformation, uint tokenInformationLength, out uint returnLength);

        #endregion

}

然后调用它:

int? sessionid = Loader2.GetActiveSessionId();
   if (isRunAsUser() && sessionid.HasValue)
      {
         log.AppendLine("关闭以system启动的程序");
         var pid = Loader2.CreateProcess(sessionid.Value, 			 
         path,args);
         if (pid > 0)
             {
               //以User启动成功
             }
      }

 private bool isRunAsUser()
        {
            bool isHave = false;
            ComputerLoginUserInfo uif = new ComputerLoginUserInfo();
            if (uif != null && uif.ComputerLoginUserInfoList != null)
            {
                var lst = uif.ComputerLoginUserInfoList.Where(p => !string.IsNullOrEmpty(p.UserName)).ToList();
                if (lst.Count >= 1)
                {
                    isHave = true;
                }
            }
            return isHave;
        }

//---引用
using System.Runtime.InteropServices;
using System.Text;

/// <summary>
/// Windows 任务管理器登录用户信息
/// author:dongee
/// date:2010.10.14
/// </summary>
public class ComputerLoginUserInfo
{
    #region 本机连接用户信息API封装
    public class TSControl
    {
        [DllImport("wtsapi32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool WTSEnumerateSessions(int hServer, int Reserved,
            int Version, ref long ppSessionInfo, ref int pCount);
        [DllImport("wtsapi32.dll")]
        public static extern void WTSFreeMemory(System.IntPtr pMemory);
        [DllImport("wtsapi32.dll")]
        public static extern bool WTSLogoffSession(int hServer, long SessionId, bool bWait);
        [DllImport("Wtsapi32.dll")]
        public static extern bool WTSQuerySessionInformation(
        System.IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass,
            out StringBuilder ppBuffer, out int pBytesReturned);
        public enum WTSInfoClass
        {
            WTSInitialProgram,
            WTSApplicationName,
            WTSWorkingDirectory,
            WTSOEMId,
            WTSSessionId,
            WTSUserName,
            WTSWinStationName,
            WTSDomainName,
            WTSConnectState,
            WTSClientBuildNumber,
            WTSClientName,
            WTSClientDirectory,
            WTSClientProductId,
            WTSClientHardwareId,
            WTSClientAddress,
            WTSClientDisplay,
            WTSClientProtocolType
        }
        public enum WTS_CONNECTSTATE_CLASS
        {
            WTSActive,
            WTSConnected,
            WTSConnectQuery,
            WTSShadow,
            WTSDisconnected,
            WTSIdle,
            WTSListen,
            WTSReset,
            WTSDown,
            WTSInit,
        }

        public struct WTS_SESSION_INFO
        {
            public int SessionID;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string pWinStationName;
            public WTS_CONNECTSTATE_CLASS state;
        }

        public static WTS_SESSION_INFO[] SessionEnumeration()
        {
            //Set handle of terminal server as the current terminal server
            int hServer = 0;
            bool RetVal;
            long lpBuffer = 0;
            int Count = 0;
            long p;
            WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
            WTS_SESSION_INFO[] arrSessionInfo;
            RetVal = WTSEnumerateSessions(hServer, 0, 1, ref lpBuffer, ref Count);
            arrSessionInfo = new WTS_SESSION_INFO[0];
            if (RetVal)
            {
                arrSessionInfo = new WTS_SESSION_INFO[Count];
                int i;
                p = lpBuffer;
                for (i = 0; i < Count; i++)
                {
                    arrSessionInfo[i] = (WTS_SESSION_INFO)Marshal.PtrToStructure(new IntPtr(p),
                        Session_Info.GetType());
                    p += Marshal.SizeOf(Session_Info.GetType());
                }
                WTSFreeMemory(new IntPtr(lpBuffer));
            }
            else
            {
                //Insert Error Reaction Here  
            }
            return arrSessionInfo;
        }
    }
    #endregion

    public System.Collections.Generic.List<ComputerLoginUserInfoModel> ComputerLoginUserInfoList;
    public ComputerLoginUserInfo()
    {
        #region 查询代码
        TSControl.WTS_SESSION_INFO[] pSessionInfo = TSControl.SessionEnumeration();
        ComputerLoginUserInfoModel cum = null;
        ComputerLoginUserInfoList = new System.Collections.Generic.List<ComputerLoginUserInfoModel>();
        for (int i = 0; i < pSessionInfo.Length; i++)
        {
            if ("RDP-Tcp" != pSessionInfo[i].pWinStationName)
            {
                try
                {
                    int count = 0;
                    IntPtr buffer = IntPtr.Zero;
                    StringBuilder userName = new StringBuilder();           // 用户名
                    StringBuilder clientUser = new StringBuilder();         // 客户端名
                    StringBuilder stateType = new StringBuilder();          // 会话类型

                    bool userNameBool = TSControl.WTSQuerySessionInformation(IntPtr.Zero,
                        pSessionInfo[i].SessionID, TSControl.WTSInfoClass.WTSUserName,
                        out userName, out count);
                    bool clientUserBool = TSControl.WTSQuerySessionInformation(IntPtr.Zero,
                        pSessionInfo[i].SessionID, TSControl.WTSInfoClass.WTSClientName,
                        out clientUser, out count);
                    bool stateTypeBool = TSControl.WTSQuerySessionInformation(IntPtr.Zero,
                        pSessionInfo[i].SessionID, TSControl.WTSInfoClass.WTSWinStationName,
                        out stateType, out count);
                    if (userNameBool && clientUserBool && stateTypeBool)
                    {
                        cum = new ComputerLoginUserInfoModel();
                        cum.UserName = userName.ToString();
                        cum.ClientUserName = clientUser.ToString();
                        cum.SessionType = stateType.ToString();
                    }
                    ComputerLoginUserInfoList.Add(cum);
                }
                catch (Exception ex) { }
            }
        }
        #endregion
    }



}
public class ComputerLoginUserInfoModel
{
    #region 用户信息字段
    private string userName;
    private string clientUserName;
    private string sessionType;

    /// <summary>
    /// 会话类型
    /// </summary>
    public string SessionType
    {
        get { return sessionType; }
        set { sessionType = value; }
    }
    /// <summary>
    /// 客户端名
    /// </summary>
    public string ClientUserName
    {
        get { return clientUserName; }
        set { clientUserName = value; }
    }
    /// <summary>
    /// 登录用户名
    /// </summary>
    public string UserName
    {
        get { return userName; }
        set { userName = value; }
    }
    #endregion
}