【问题标题】:Start a windows service and launch cmd启动 Windows 服务并启动 cmd
【发布时间】:2011-05-08 01:31:35
【问题描述】:

我是否需要启用交互式桌面才能工作?启动 EXE 或 cmd 窗口的正确代码是什么?即使启用了与桌面交互的服务,我仍然无法启动该服务。

我将使用聊天引擎,因此它更易于作为 Windows 服务进行管理。

我的代码有什么问题?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading;

namespace MyNewService
{
    class Program : ServiceBase
    {
        static void Main(string[] args)
        {
        }

        public Program()
        {
            this.ServiceName = "Chatter";
        }

        protected override void OnStart(string[] args)
        {
            base.OnStart(args);

            //TODO: place your start code here
            ThreadStart starter = new ThreadStart(bw_DoWork);
            Thread t = new Thread(starter);
            t.Start();

        }

        private void bw_DoWork()
        {
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(@"C:\Windows\system32\cmd.exe");
            p.Start();
            p.WaitForExit();
            base.Stop();
        }

        protected override void OnStop()
        {
            base.OnStop();

            //TODO: clean up any variables and stop any threads
        }
    }
}

【问题讨论】:

    标签: c# windows windows-services cmd


    【解决方案1】:

    我已经经历了这样做的所有痛苦。

    在 Windows 7/Vista/2008 下,无法从服务加载任何交互式进程 - 无需调用多个 Win API。 = 黑魔法

    看看herehere

    下面的代码可以解决问题,使用它需要您自担风险:

    public static class ProcessAsCurrentUser
    {
    
        /// <summary>
        /// Connection state of a session.
        /// </summary>
        public enum ConnectionState
        {
            /// <summary>
            /// A user is logged on to the session.
            /// </summary>
            Active,
            /// <summary>
            /// A client is connected to the session.
            /// </summary>
            Connected,
            /// <summary>
            /// The session is in the process of connecting to a client.
            /// </summary>
            ConnectQuery,
            /// <summary>
            /// This session is shadowing another session.
            /// </summary>
            Shadowing,
            /// <summary>
            /// The session is active, but the client has disconnected from it.
            /// </summary>
            Disconnected,
            /// <summary>
            /// The session is waiting for a client to connect.
            /// </summary>
            Idle,
            /// <summary>
            /// The session is listening for connections.
            /// </summary>
            Listening,
            /// <summary>
            /// The session is being reset.
            /// </summary>
            Reset,
            /// <summary>
            /// The session is down due to an error.
            /// </summary>
            Down,
            /// <summary>
            /// The session is initializing.
            /// </summary>
            Initializing
        }
    
    
        [StructLayout(LayoutKind.Sequential)]
        class SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }
    
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        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 dwYSize;
            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)]
        internal struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }
    
        enum LOGON_TYPE
        {
            LOGON32_LOGON_INTERACTIVE = 2,
            LOGON32_LOGON_NETWORK,
            LOGON32_LOGON_BATCH,
            LOGON32_LOGON_SERVICE,
            LOGON32_LOGON_UNLOCK = 7,
            LOGON32_LOGON_NETWORK_CLEARTEXT,
            LOGON32_LOGON_NEW_CREDENTIALS
        }
    
        enum LOGON_PROVIDER
        {
            LOGON32_PROVIDER_DEFAULT,
            LOGON32_PROVIDER_WINNT35,
            LOGON32_PROVIDER_WINNT40,
            LOGON32_PROVIDER_WINNT50
        }
    
        [Flags]
        enum CreateProcessFlags : uint
        {
            CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
            CREATE_DEFAULT_ERROR_MODE = 0x04000000,
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200,
            CREATE_NO_WINDOW = 0x08000000,
            CREATE_PROTECTED_PROCESS = 0x00040000,
            CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
            CREATE_SEPARATE_WOW_VDM = 0x00000800,
            CREATE_SHARED_WOW_VDM = 0x00001000,
            CREATE_SUSPENDED = 0x00000004,
            CREATE_UNICODE_ENVIRONMENT = 0x00000400,
            DEBUG_ONLY_THIS_PROCESS = 0x00000002,
            DEBUG_PROCESS = 0x00000001,
            DETACHED_PROCESS = 0x00000008,
            EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
            INHERIT_PARENT_AFFINITY = 0x00010000
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct WTS_SESSION_INFO
        {
            public int SessionID;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string WinStationName;
            public ConnectionState State;
        }
    
        [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Int32 WTSEnumerateSessions(IntPtr hServer, int reserved, int version,
                                                        ref IntPtr sessionInfo, ref int count);
    
    
        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserW", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool CreateProcessAsUser(
            IntPtr hToken,
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            UInt32 dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);
    
        [DllImport("wtsapi32.dll")]
        public static extern void WTSFreeMemory(IntPtr memory);
    
        [DllImport("kernel32.dll")]
        private static extern UInt32 WTSGetActiveConsoleSessionId();
    
        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern int WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
    
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateTokenEx(
            IntPtr hExistingToken,
            uint dwDesiredAccess,
            IntPtr lpTokenAttributes,
            int ImpersonationLevel,
            int TokenType,
            out IntPtr phNewToken);
    
        private const int TokenImpersonation = 2;
        private const int SecurityIdentification = 1;
        private const int MAXIMUM_ALLOWED = 0x2000000;
        private const int TOKEN_DUPLICATE = 0x2;
        private const int TOKEN_QUERY = 0x00000008;
    
        /// <summary>
        /// Launches a process for the current logged on user if there are any.
        /// If none, return false as well as in case of 
        /// 
        /// ##### !!! BEWARE !!! ####  ------------------------------------------
        /// This code will only work when running in a windows service (where it is really needed)
        /// so in case you need to test it, it needs to run in the service. Reason
        /// is a security privileg which only services have (SE_??? something, cant remember)!
        /// </summary>
        /// <param name="processExe"></param>
        /// <returns></returns>
        public static bool CreateProcessAsCurrentUser(string processExe)
        {
    
            IntPtr duplicate = new IntPtr();
            STARTUPINFO info = new STARTUPINFO();
            PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();
    
            Debug.WriteLine(string.Format("CreateProcessAsCurrentUser. processExe: " + processExe));
    
            IntPtr p = GetCurrentUserToken();
    
            bool result = DuplicateTokenEx(p, MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE, IntPtr.Zero, SecurityIdentification, SecurityIdentification, out duplicate);
            Debug.WriteLine(string.Format("DuplicateTokenEx result: {0}", result));
            Debug.WriteLine(string.Format("duplicate: {0}", duplicate));
    
    
            if (result)
            {
                result = CreateProcessAsUser(duplicate, processExe, null,
                    IntPtr.Zero, IntPtr.Zero, false, (UInt32)CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, null,
                    ref info, out procInfo);
                Debug.WriteLine(string.Format("CreateProcessAsUser result: {0}", result));
    
            }
    
    
            if (p.ToInt32() != 0)
            {
                Marshal.Release(p);
                Debug.WriteLine(string.Format("Released handle p: {0}", p));
            }
    
    
            if (duplicate.ToInt32() != 0)
            {
                Marshal.Release(duplicate);
                Debug.WriteLine(string.Format("Released handle duplicate: {0}", duplicate));
            }
    
    
    
            return result;
        }
    
        public static int GetCurrentSessionId()
        {
            uint sessionId = WTSGetActiveConsoleSessionId();
            Debug.WriteLine(string.Format("sessionId: {0}", sessionId));
    
            if (sessionId == 0xFFFFFFFF)
                return -1;
            else
                return (int)sessionId;
        }
    
        public static bool IsUserLoggedOn()
        {
            List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
            Debug.WriteLine(string.Format("Number of sessions: {0}", wtsSessionInfos.Count));
            return wtsSessionInfos.Where(x => x.State == ConnectionState.Active).Count() > 0;
        }
    
        private static IntPtr GetCurrentUserToken()
        {
            List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
            int sessionId = wtsSessionInfos.Where(x => x.State == ConnectionState.Active).FirstOrDefault().SessionID;
            //int sessionId = GetCurrentSessionId();
    
            Debug.WriteLine(string.Format("sessionId: {0}", sessionId));
            if (sessionId == int.MaxValue)
            {
                return IntPtr.Zero;
            }
            else
            {
                IntPtr p = new IntPtr();
                int result = WTSQueryUserToken((UInt32)sessionId, out p);
                Debug.WriteLine(string.Format("WTSQueryUserToken result: {0}", result));
                Debug.WriteLine(string.Format("WTSQueryUserToken p: {0}", p));
    
                return p;
            }
        }
    
        public static List<WTS_SESSION_INFO> ListSessions()
        {
            IntPtr server = IntPtr.Zero;
            List<WTS_SESSION_INFO> ret = new List<WTS_SESSION_INFO>();
    
            try
            {
                IntPtr ppSessionInfo = IntPtr.Zero;
    
                Int32 count = 0;
                Int32 retval = WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count);
                Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
    
                Int64 current = (int)ppSessionInfo;
    
                if (retval != 0)
                {
                    for (int i = 0; i < count; i++)
                    {
                        WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
                        current += dataSize;
    
                        ret.Add(si);
                    }
    
                    WTSFreeMemory(ppSessionInfo);
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception.ToString());
            }
    
            return ret;
        }
    
    }
    

    【讨论】:

    • 很难编程。所以我放弃了,因为它不值得努力。
    • 我可以把代码挖出来发给你。今晚我回家后会这样做。
    • 注意:如果运行与控制台应用程序相同的可执行文件,这将不起作用。在这种情况下,我只使用 Process.Start。
    • @Aliostad 看起来不错,但是如何在“服务方法”中设置链接,您可以发布或解释一下吗?
    • @Aliostad 哇,非常感谢! CREATE_NEW_CONSOLE 对我来说是 cmd.exe 的缺失部分(没有它,GUI 运行正常;顺便说一句,我正在使用 CREATE_UNICODE_ENVIRONMENT 和其他一些标志,但这在这里无关紧要)。我想问你是否还记得你为什么不在这里使用 WTSGetActiveConsoleSessionId() ?现在似乎正在为我工​​作......另外,我没有使用 DuplicateTokenEx();你可能记得/知道这是否重要,为什么?发送
    【解决方案2】:

    当作为服务运行时,您将无法启动任何需要与桌面交互的东西,或者会生成它自己的窗口。

    正如 Aliostad 所说,您需要调用 Win API 调用 CreateProcessAsUser 并模拟用户才能使其正常工作。这涉及模拟登录用户并使用他们的凭据将您的进程“提升”到进程隔离级别 1(这使您可以访问窗口系统和 GPU 之类的东西)。

    我在我编写的应用程序中执行此操作,它确实有效,但我同意 Aliostad 的观点,其中有一点黑魔法,而且通常很糟糕

    话虽如此,您可以从服务中生成工作进程,只要它们不需要处于进程隔离级别 1 的事物(窗口化、GPU 等)。

    cmd.exe 默认情况下会尝试创建一个窗口,这就是您的示例失败的原因。您可以设置以下 ProcessStartInfo 属性以使其正常工作。

    创建无窗口 窗口样式

    【讨论】:

    • “进程隔离级别 1”不存在。您的意思是“用户的交互式会话”。
    【解决方案3】:

    我编写了一个应用程序看门狗服务,它只是重新启动一个应用程序(在我的例子中是一个控制台窗口应用程序)。

    1. 我找到了一个非常好的动手实验室教程(C++ 语言),我尝试过它在 Session 0 Isolation 中工作:http://msdn.microsoft.com/en-us/Windows7TrainingCourse_Win7Session0Isolation

    2. 我将该 C++ 示例转换为 C#。经过几次测试,它工作了。只要我保持登录状态并且不注销并再次登录,该代码就可以完美运行。我必须做一些事情来捕捉会话注销/登录。但对于 Windows 中的简单登录和工作条件,看门狗按预期工作。

    3. 这是所需的 PInvoke 代码:

      [StructLayout(LayoutKind.Sequential)]
      public struct STARTUPINFO
      {
          public int 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 short wShowWindow;
          public short 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 uint dwProcessId;
          public uint dwThreadId;
      }
      
      
      public enum TOKEN_TYPE
      {
          TokenPrimary = 1,
          TokenImpersonation
      }
      
      public enum SECURITY_IMPERSONATION_LEVEL
      {
          SecurityAnonymous,
          SecurityIdentification,
          SecurityImpersonation,
          SecurityDelegation
      }
      
      [StructLayout(LayoutKind.Sequential)]
      public struct SECURITY_ATTRIBUTES
      {
          public int nLength;
          public IntPtr lpSecurityDescriptor;
          public int bInheritHandle;
      }
      
      
      [DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
      public extern static bool CloseHandle(IntPtr handle);
      
      [DllImport("kernel32.dll")]
      public static extern uint WTSGetActiveConsoleSessionId();
      
      [DllImport("wtsapi32.dll", SetLastError = true)]
      public static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
      
      [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
      public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
          ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
          String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
      
      
      [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
      public extern static bool DuplicateTokenEx(
          IntPtr hExistingToken,
          uint dwDesiredAccess,
          ref SECURITY_ATTRIBUTES lpTokenAttributes,
          SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
          TOKEN_TYPE TokenType,
          out IntPtr phNewToken);
      
    4. 这是封装的方法:

          private void CreateUserProcess()
      {
      
          bool ret;
          SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
      
          uint dwSessionID = WTSGetActiveConsoleSessionId();
      
      
          this.EventLog.WriteEntry("WTSGetActiveConsoleSessionId: " + dwSessionID, EventLogEntryType.FailureAudit);
      
      
          IntPtr Token = new IntPtr();
          ret = WTSQueryUserToken((UInt32)dwSessionID, out Token);
      
          if (ret == false)
          {
              this.EventLog.WriteEntry("WTSQueryUserToken failed with " + Marshal.GetLastWin32Error(), EventLogEntryType.FailureAudit);
      
          }
      
          const uint MAXIMUM_ALLOWED  = 0x02000000;
          IntPtr DupedToken = IntPtr.Zero;
      
          ret = DuplicateTokenEx(Token,
              MAXIMUM_ALLOWED,
              ref sa,
              SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
              TOKEN_TYPE.TokenPrimary,
              out DupedToken);
      
          if (ret == false)
          {
              this.EventLog.WriteEntry("DuplicateTokenEx failed with " + Marshal.GetLastWin32Error(), EventLogEntryType.FailureAudit);
      
          }
          else
          {
              this.EventLog.WriteEntry("DuplicateTokenEx SUCCESS", EventLogEntryType.SuccessAudit); 
          }
      
          STARTUPINFO si = new STARTUPINFO();
          si.cb = Marshal.SizeOf(si);
          //si.lpDesktop = "";
      
          string commandLinePath;
      
          // commandLinePath example: "c:\myapp.exe c:\myconfig.xml" . cmdLineArgs can be ommited
          commandLinePath = AppPath + " " + CmdLineArgs;
      
          PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
          //CreateProcessAsUser(hDuplicatedToken, NULL, lpszClientPath, NULL, NULL, FALSE,
          //                    0,
          //                    NULL, NULL, &si, &pi)
          ret = CreateProcessAsUser(DupedToken, null, commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, null, ref si, out pi);
      
          if (ret == false)
          {
              this.EventLog.WriteEntry("CreateProcessAsUser failed with " + Marshal.GetLastWin32Error(), EventLogEntryType.FailureAudit);
      
      
          }
          else
          {
              this.EventLog.WriteEntry("CreateProcessAsUser SUCCESS.  The child PID is" + pi.dwProcessId, EventLogEntryType.SuccessAudit);
              CloseHandle(pi.hProcess);
              CloseHandle(pi.hThread);
          }
      
          ret = CloseHandle(DupedToken);
          if (ret == false)
          {
              this.EventLog.WriteEntry("CloseHandle LastError: " + Marshal.GetLastWin32Error(), EventLogEntryType.Error);
          }
          else
          {
          this.EventLog.WriteEntry("CloseHandle SUCCESS", EventLogEntryType.Information);
      
          }
      }
      

    希望有用!

    【讨论】:

      【解决方案4】:

      以下函数将作为活动用户从 Windows 服务启动可执行文件。

      //Function to run a process as active user from windows service
      void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args)
      {
          DWORD session_id = -1;
          DWORD session_count = 0;
      
          WTS_SESSION_INFOA *pSession = NULL;
      
      
          if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
          {
              //log success
          }
          else
          {
              //log error
              return;
          }
      
          for (int i = 0; i < session_count; i++)
          {
              session_id = pSession[i].SessionId;
      
              WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
              WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
      
              DWORD bytes_returned = 0;
              if (::WTSQuerySessionInformation(
                  WTS_CURRENT_SERVER_HANDLE,
                  session_id,
                  WTSConnectState,
                  reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
                  &bytes_returned))
              {
                  wts_connect_state = *ptr_wts_connect_state;
                  ::WTSFreeMemory(ptr_wts_connect_state);
                  if (wts_connect_state != WTSActive) continue;
              }
              else
              {
                  //log error
                  continue;
              }
      
              HANDLE hImpersonationToken;
      
              if (!WTSQueryUserToken(session_id, &hImpersonationToken))
              {
                  //log error
                  continue;
              }
      
      
              //Get real token from impersonation token
              DWORD neededSize1 = 0;
              HANDLE *realToken = new HANDLE;
              if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
              {
                  CloseHandle(hImpersonationToken);
                  hImpersonationToken = *realToken;
              }
              else
              {
                  //log error
                  continue;
              }
      
      
              HANDLE hUserToken;
      
              if (!DuplicateTokenEx(hImpersonationToken,
                  //0,
                  //MAXIMUM_ALLOWED,
                  TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
                  NULL,
                  SecurityImpersonation,
                  TokenPrimary,
                  &hUserToken))
              {
                  //log error
                  continue;
              }
      
              // Get user name of this process
              //LPTSTR pUserName = NULL;
              WCHAR* pUserName;
              DWORD user_name_len = 0;
      
              if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
              {
                  //log username contained in pUserName WCHAR string
              }
      
              //Free memory                         
              if (pUserName) WTSFreeMemory(pUserName);
      
              ImpersonateLoggedOnUser(hUserToken);
      
              STARTUPINFOW StartupInfo;
              GetStartupInfoW(&StartupInfo);
              StartupInfo.cb = sizeof(STARTUPINFOW);
              //StartupInfo.lpDesktop = "winsta0\\default";
      
              PROCESS_INFORMATION processInfo;
      
              SECURITY_ATTRIBUTES Security1;
              Security1.nLength = sizeof SECURITY_ATTRIBUTES;
      
              SECURITY_ATTRIBUTES Security2;
              Security2.nLength = sizeof SECURITY_ATTRIBUTES;
      
              void* lpEnvironment = NULL;
      
              // Get all necessary environment variables of logged in user
              // to pass them to the new process
              BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
              if (!resultEnv)
              {
                  //log error
                  continue;
              }
      
              WCHAR PP[1024]; //path and parameters
              ZeroMemory(PP, 1024 * sizeof WCHAR);
              wcscpy(PP, path);
              wcscat(PP, L" ");
              wcscat(PP, args);
      
              // Start the process on behalf of the current user 
              BOOL result = CreateProcessAsUserW(hUserToken, 
                  NULL,
                  PP,
                  //&Security1,
                  //&Security2,
                  NULL,
                  NULL,
                  FALSE, 
                  NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                  //lpEnvironment,
                  NULL,
                  //"C:\\ProgramData\\some_dir",
                  NULL,
                  &StartupInfo,
                  &processInfo);
      
              if (!result)
              {
                  //log error
              }
              else
              {
                  //log success
              }
      
              DestroyEnvironmentBlock(lpEnvironment);
      
              CloseHandle(hImpersonationToken);
              CloseHandle(hUserToken);
              CloseHandle(realToken);
      
              RevertToSelf();
          }
      
          WTSFreeMemory(pSession);
      }
      

      【讨论】:

      • 我将放弃对这项工作的支持,但问题是针对 C#,而不是针对 C++。
      • 是的,你是对的。说实话,当我遇到这个问题时,我并没有意识到它是 C#,我只是发布了我碰巧有的相关代码。我想它仍然可以用于显示所涉及的逻辑和低级调用是什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      相关资源
      最近更新 更多