locked
Windows service failed when remote desktop RRS feed

  • Question

  • Dear all,

    I have the windows service program running on windows 7 or XP. When windows start and login, this windows service will start. But when log off and remote desktop connection and log in, the windows service does not start. Do you experience this issues?? Do you know how to solve??

    Windows service does really failed to load when doing remote desktop. In the event viewer ,

    It show error event id: 5000, source: .Net Runtime 2.0 Error in event viewer log

    Description:

    EventType clr20r3. P1 Monitor.exe. P2 1.0.0.0.P3 4dd1eec3, P4 system, P5 2.0.0.0, P6 471ebf0d, P7 3a23, P8 22, P9 system.componentmodel.win32, P10 NIL

    It seems to be access denied. Are there any difference between normal login and remote desktop login?? Do you have any ideas to solve??

    I have below code in starting the exe file.

    private Process m_Process; 
     
    public void runMonitor() 
    { 
     
    ApplicationLoader.PROCESS_INFORMATION procInfo; 
    ApplicationLoader.StartProcessAndBypassUAC("Monitor.exe", out procInfo); 
           
      
    this.m_Process = Process.GetProcessById((int)procInfo.dwProcessId); 
     
     
    ...................... 
     
    } 
     
    // ------------ ApplicationLoader file--------------------------------// 
     
    using System; 
    using System.Security; 
    using System.Diagnostics; 
    using System.Runtime.InteropServices; 
     
    namespace StoreService 
    { 
      /// <summary> 
      /// Class that allows running applications with full admin rights. In 
      /// addition the application launched will bypass the Vista UAC prompt. 
      /// </summary> 
      public class ApplicationLoader 
      { 
        #region Structures 
     
        [StructLayout(LayoutKind.Sequential)] 
        public struct SECURITY_ATTRIBUTES 
        { 
          public int Length; 
          public IntPtr lpSecurityDescriptor; 
          public bool bInheritHandle; 
        } 
     
        [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; 
        } 
     
        #endregion 
     
        #region Enumerations 
     
        enum TOKEN_TYPE : int 
        { 
          TokenPrimary = 1, 
          TokenImpersonation = 2 
        } 
     
        enum SECURITY_IMPERSONATION_LEVEL : int 
        { 
          SecurityAnonymous = 0, 
          SecurityIdentification = 1, 
          SecurityImpersonation = 2, 
          SecurityDelegation = 3, 
        } 
     
        #endregion 
     
        #region Constants 
     
        public const int TOKEN_DUPLICATE = 0x0002; 
        public const uint MAXIMUM_ALLOWED = 0x2000000; 
        public const int CREATE_NEW_CONSOLE = 0x00000010; 
     
        public const int IDLE_PRIORITY_CLASS = 0x40; 
        public const int NORMAL_PRIORITY_CLASS = 0x20; 
        public const int HIGH_PRIORITY_CLASS = 0x80; 
        public const int REALTIME_PRIORITY_CLASS = 0x100; 
     
        #endregion 
     
        #region Win32 API Imports 
     
        [DllImport("kernel32.dll", SetLastError = true)] 
        private static extern bool CloseHandle(IntPtr hSnapshot); 
     
        [DllImport("kernel32.dll")] 
        static extern uint WTSGetActiveConsoleSessionId(); 
     
        [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("kernel32.dll")] 
        static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId); 
     
        [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")] 
        public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, 
          ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, 
          int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); 
     
        [DllImport("kernel32.dll")] 
        static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); 
     
        [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] 
        static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle); 
     
        #endregion 
     
        /// <summary> 
        /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt 
        /// </summary> 
        /// <param name="applicationName">The name of the application to launch</param> 
        /// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param> 
        /// <returns></returns> 
        public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo) 
        { 
          uint winlogonPid = 0; 
          IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; 
          procInfo = new PROCESS_INFORMATION(); 
     
          // obtain the currently active session id; every logged on user in the system has a unique session id 
          uint dwSessionId = WTSGetActiveConsoleSessionId(); 
     
          // obtain the process id of the winlogon process that is running within the currently active session 
          Process[] processes = Process.GetProcessesByName("winlogon"); 
          foreach (Process p in processes) 
          { 
            if ((uint)p.SessionId == dwSessionId) 
            { 
              winlogonPid = (uint)p.Id; 
            } 
          } 
     
          // obtain a handle to the winlogon process 
          hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); 
     
          // obtain a handle to the access token of the winlogon process 
          if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) 
          { 
            CloseHandle(hProcess); 
            return false; 
          } 
     
          // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser 
          // I would prefer to not have to use a security attribute variable and to just 
          // simply pass null and inherit (by default) the security attributes 
          // of the existing token. However, in C# structures are value types and therefore 
          // cannot be assigned the null value. 
          SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); 
          sa.Length = Marshal.SizeOf(sa); 
     
          // copy the access token of the winlogon process; the newly created token will be a primary token 
          if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) 
          { 
            CloseHandle(hProcess); 
            CloseHandle(hPToken); 
            return false; 
          } 
     
          // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning 
          // the window station has a desktop that is invisible and the process is incapable of receiving 
          // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user 
          // interaction with the new process. 
          STARTUPINFO si = new STARTUPINFO(); 
          si.cb = (int)Marshal.SizeOf(si); 
          si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop 
     
          // flags that specify the priority and creation method of the process 
          int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; 
     
          // create a new process in the current user's logon session 
          bool result = CreateProcessAsUser(hUserTokenDup,    // client's access token 
                          null,          // file to execute 
                          applicationName,    // command line 
                          ref sa,         // pointer to process SECURITY_ATTRIBUTES 
                          ref sa,         // pointer to thread SECURITY_ATTRIBUTES 
                          false,         // handles are not inheritable 
                          dwCreationFlags,    // creation flags 
                          IntPtr.Zero,      // pointer to new environment block 
                          null,          // name of current directory 
                          ref si,         // pointer to STARTUPINFO structure 
                          out procInfo      // receives information about new process 
                          ); 
     
          // invalidate the handles 
          CloseHandle(hProcess); 
          CloseHandle(hPToken); 
          CloseHandle(hUserTokenDup); 
     
          return result; // return the result 
        } 
     
      } 
    }
    

     

    Monday, July 18, 2011 4:33 AM

All replies

  • yes, there is a differnece in logging in locally or remoe via rdp.

    You can see your sessions using the qwinsta command. youw ill see that the "console" session always is session 0.

    Allthough I did not read or check your entire code, i see a reference to the desktop in session 0   si.lpDesktop = @"winsta0\default""; it seems logic you cannot create windows etc on a desktop that is not yours.

     

    ANOTHER remark: you probably better post your question in one of the veleopment forumsas tehre there are probably more developers ith the needed experience (here, as far as I know, there is a more system engeneering perspective)


    MCP/MCSA/MCTS/MCITP
    Monday, July 18, 2011 1:46 PM