none
Child process not working with C# windows service RRS feed

  • Question

  • I am  running interactive application by the windows service. I have download code form the below link

    code.msdn.microsoft.com/windowsapps/CSCreateProcessAsUserFromSe-b682134e

    (add https with link)

    Its working for   "notepad" but not other. Can you help me reason behind this. 

    And also i want to run any app with auto administrative permission for run the exe. does it possible in the given code.

    I am attaching some code also for you. 

    Program.cs

    using System;
    using System.ServiceProcess;
    
    namespace CSCreateProcessAsUserFromService
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            static void Main()
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
    			{ 
    				new Service1() 
    			};
                ServiceBase.Run(ServicesToRun);
            }
        }
    }

    Service1.cs

    using System;
    using System.ServiceProcess;
    using System.Runtime.InteropServices;
    
    namespace CSCreateProcessAsUserFromService
    {
        public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                // As creating a child process might be a time consuming operation,
                // its better to do that in a separate thread than blocking the main thread.
                System.Threading.Thread ProcessCreationThread = new System.Threading.Thread(MyThreadFunc);
                ProcessCreationThread.Start();
            }
    
            protected override void OnStop()
            {
            }
    
            // This thread function would launch a child process 
            // in the interactive session of the logged-on user.
            public static void MyThreadFunc()
            {
                CreateProcessAsUserWrapper.LaunchChildProcess(@"D:\om_Backup\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe");
                //CreateProcessAsUserWrapper.LaunchChildProcess(@"notepad.exe");
            }
        }
    }

    CreateProcessAsUserWrapper.cs code as

    /************************************* Module Header ***********************************\
    * Module Name:  CreateProcessAsUserWrapper.cs
    * Project:      CSCreateProcessAsUserFromService
    * Copyright (c) Microsoft Corporation.
    * 
    * The sample demonstrates how to create/launch a process interactively in the session of 
    * the logged-on user from a service application written in C#.Net.
    * 
    * This source is subject to the Microsoft Public License.
    * See http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
    * All other rights reserved.
    * 
    * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
    * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
    * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
    \***************************************************************************************/
    
    using System;
    using System.Runtime.InteropServices;
    
    namespace CSCreateProcessAsUserFromService
    {
        class CreateProcessAsUserWrapper
        {
            public static void LaunchChildProcess(string ChildProcName)
            {
                IntPtr ppSessionInfo = IntPtr.Zero;
                UInt32 SessionCount = 0;
    
                if (WTSEnumerateSessions(
                    (IntPtr)WTS_CURRENT_SERVER_HANDLE,  // Current RD Session Host Server handle would be zero.
                    0,                                  // This reserved parameter must be zero.
                    1,                                  // The version of the enumeration request must be 1.
                    ref ppSessionInfo,                  // This would point to an array of session info.
                    ref SessionCount                    // This would indicate the length of the above array.
                    ))
                {
                    for (int nCount = 0; nCount < SessionCount; nCount++)
                    {
                        // Extract each session info and check if it is the 
                        // "Active Session" of the current logged-on user.
                        WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(
                            ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)),
                            typeof(WTS_SESSION_INFO)
                            );
    
                        if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
                        {
                            IntPtr hToken = IntPtr.Zero;
                            if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
                            {
                                // Launch the child process interactively 
                                // with the token of the logged-on user.
                                PROCESS_INFORMATION tProcessInfo;
                                STARTUPINFO tStartUpInfo = new STARTUPINFO();
                                tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
    
                                bool ChildProcStarted = CreateProcessAsUser(
                                    hToken,             // Token of the logged-on user.
                                    ChildProcName,      // Name of the process to be started.
                                    null,               // Any command line arguments to be passed.
                                    IntPtr.Zero,        // Default Process' attributes.
                                    IntPtr.Zero,        // Default Thread's attributes.
                                    false,              // Does NOT inherit parent's handles.
                                    0,                  // No any specific creation flag.
                                    null,               // Default environment path.
                                    null,               // Default current directory.
                                    ref tStartUpInfo,   // Process Startup Info. 
                                    out tProcessInfo    // Process information to be returned.
                                    );
    
                                if (ChildProcStarted)
                                {
                                    // The child process creation is successful!
    
                                    // If the child process is created, it can be controlled via the out 
                                    // param "tProcessInfo". For now, as we don't want to do any thing 
                                    // with the child process, closing the child process' handles 
                                    // to prevent the handle leak.
                                    CloseHandle(tProcessInfo.hThread);
                                    CloseHandle(tProcessInfo.hProcess);
                                }
                                else
                                {
                                    // CreateProcessAsUser failed!
                                }
    
                                // Whether child process was created or not, close the token handle 
                                // and break the loop as processing for current active user has been done.
                                CloseHandle(hToken);
                                break;
                            }
                            else
                            {
                                // WTSQueryUserToken failed!
                            }
                        }
                        else
                        {
                            // This Session is not active!
                        }
                    }
    
                    // Free the memory allocated for the session info array.
                    WTSFreeMemory(ppSessionInfo);
                }
                else
                {
                    // WTSEnumerateSessions failed!
                }
            }
    
    
            #region P/Invoke WTS APIs
            /// <summary>
            /// Struct, Enum and P/Invoke Declarations of WTS APIs.
            /// </summary>
            /// 
    
            private const int WTS_CURRENT_SERVER_HANDLE = 0;
            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            private struct WTS_SESSION_INFO
            {
                public UInt32 SessionID;
                public string pWinStationName;
                public WTS_CONNECTSTATE_CLASS State;
            }
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSEnumerateSessions(
                IntPtr hServer,
                [MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
                [MarshalAs(UnmanagedType.U4)] UInt32 Version,
                ref IntPtr ppSessionInfo,
                [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
                );
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern void WTSFreeMemory(IntPtr pMemory);
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
            #endregion
    
    
            #region P/Invoke CreateProcessAsUser
            /// <summary>
            /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser.
            /// </summary>
            /// 
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            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, CharSet = CharSet.Auto)]
            struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public int dwProcessId;
                public int dwThreadId;
            }
    
            [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandles,
                uint dwCreationFlags,
                string lpEnvironment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation
                );
    
            [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CloseHandle(IntPtr hHandle);
            #endregion
        }
    }

    thanks





    Monday, June 18, 2018 6:31 PM

All replies

  • Hi Jitendra ,

    For your question, I test the code from link above. When you switch from "notepad" to other one(such as ConsoleApp1.exe, a simple console application), you should firstly stop the service. Otherwise, you would fail to rebuild CSCreateProcessAsUserFromService, which may cause that other application cannot work. 

    Besides, you can put the path "D:\om_Backup\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe" into the file address bar to check if you can open the application directly.

    As the introduction of the CSCreateProcessAsUserFromService mentions, this sample can be referenced for launching any other interactive child applications. Therefore, I think it is possible to run any app with auto administrative permission in the given code.

    Regards,

    Dolen


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    • Edited by Dolen Zhang Thursday, June 21, 2018 7:03 AM
    Thursday, June 21, 2018 7:02 AM