2010-11-10 17 views
16

Czy muszę włączyć Interactive desktp, aby działał i jaki jest poprawny kod do uruchomienia okna EXE lub cmd? Nadal nie mogę uruchomić usługi, nawet gdy udostępniłem ją do interakcji z komputerem.Uruchomić usługę Windows i uruchomić cmd

Używałbym silnika czatu, więc łatwiej jest nim zarządzać jako usługa Windows.

Co jest nie tak z moim kodem?

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 
     } 
    } 
} 

Odpowiedz

30

Przeszedłem przez cały ten ból.

W systemie Windows 7/Vista/2008 nie można załadować żadnego interaktywnego procesu z usługi - bez wywoływania numeru interfejsu API Win. = CZARNY MAGIC

Zobacz here i here.

Poniższy kod nie podstęp, użyj go na własne ryzyko:

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; 
    } 

} 
+0

Trudno jest zaprogramować. Więc poddałem się, ponieważ nie było to warte wysiłku. – Proyb2

+0

Mogę wykopać kod i wysłać go do ciebie. Zrobię to dziś wieczorem, kiedy wrócę do domu. – Aliostad

+0

Zaktualizowałem kod teraz. – Aliostad

5

gdy uruchomiony jako usługa nie będzie w stanie uruchomić wszystko, co potrzebne do interakcji z pulpitem czy będzie tarła to własne okna.

Jak powiedział Aliostad, należy wywoływać wywołania Win API do CreateProcessAsUser i emulować użytkownika, aby działał. Wiąże się to z emulowaniem zalogowanego użytkownika i wykorzystaniem jego referencji do "podniesienia" twojego procesu do poziomu izolacji procesu 1 (który daje ci dostęp do systemu okien i takich rzeczy jak GPU).

Robię to w aplikacji pisałem i to działa, ale zgadzam się z Aliostad tam jest trochę czarna magia dzieje i ogólnie ssie

Powiedziawszy to wszystko, można tarło procesów roboczych od w ramach usługi tak długo, jak nie wymagają rzeczy, które są w procesie izolowania poziomu 1 (Okienkowanie, GPU itp.)

cmd.exe domyślnie spróbuje stworzyć okno, dlatego Twój przykład się nie udaje . Można ustawić następujące właściwości ProcessStartInfo, aby działało.

CreateNoWindow WindowStyle

+0

"Poziom izolacji procesu 1" nie istnieje. To, co masz na myśli, to "interaktywna sesja użytkownika". – wj32

2

napisałem usługa nadzoru aplikacji, które po prostu zostanie zrestartowane aplikację (w moim przypadku okno konsoli APP).

  1. znalazłem bardzo dobrych rękach-On Lab Tutorial (w C++), które próbowałem na to pracował Sesja 0 izolacji pod adresem: http://msdn.microsoft.com/en-us/Windows7TrainingCourse_Win7Session0Isolation

  2. konwertowane, że C++ próbki do C#. Po kilku testach zadziałało. Dopóki pozostaję zalogowany i nie wylogowuję się ponownie, aby ten kod działał idealnie. Muszę zrobić trochę, aby złapać wylogowanie/zalogowanie sesji. Ale dla prostego logowania i Warunków Pracy w Windows watchdog działa zgodnie z oczekiwaniami.

  3. Oto wymagany kod 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. Oto encapsuled metoda:

    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); 
    
        } 
    } 
    

Mam nadzieję, że jest to przydatne!

1

Poniższa funkcja uruchomi plik wykonywalny jako aktywny użytkownik z usługi systemu 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); 
} 
+1

Zostawię tutaj przegłosowany wysiłek, ale pytanie dotyczy C#, a nie C++. – TonyG

+0

Tak, masz rację. Prawdę mówiąc, gdy natknąłem się na to pytanie, nie zdawałem sobie sprawy, że to C# i właśnie napisałem odpowiedni kod, który zdarzyło mi się mieć. Sądzę, że nadal może być przydatny w pokazywaniu logiki i połączeń o niskim poziomie. –

Powiązane problemy