첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

■ 프로세스 실행하기

------------------------------------------------------------------------------------------------------------------------

ProcessHelper.cs

 

 

using System;

using System.Diagnostics;

using System.IO;

using System.Runtime.InteropServices;

 

namespace TestProject

{

    /// <summary>

    /// 프로세스 헬퍼

    /// </summary>

    public static class ProcessHelper

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 윈도우 표시 타입 - ShowWindowType

 

        /// <summary>

        /// 윈도우 표시 타입

        /// </summary>

        private enum ShowWindowType

        {

            /// <summary>

            /// SW_HIDE

            /// </summary>

            SW_HIDE = 1,

 

            /// <summary>

            /// SW_SHOWNORMAL

            /// </summary>

            SW_SHOWNORMAL = 1,

 

            /// <summary>

            /// SW_NORMAL

            /// </summary>

            SW_NORMAL = 1,

 

            /// <summary>

            /// SW_SHOWMINIMIZED

            /// </summary>

            SW_SHOWMINIMIZED = 2,

 

            /// <summary>

            /// SW_SHOWMAXIMIZED

            /// </summary>

            SW_SHOWMAXIMIZED = 3,

 

            /// <summary>

            /// SW_MAXIMIZE

            /// </summary>

            SW_MAXIMIZE = 3,

 

            /// <summary>

            /// SW_SHOWNOACTIVATE

            /// </summary>

            SW_SHOWNOACTIVATE = 4,

 

            /// <summary>

            /// SW_SHOW

            /// </summary>

            SW_SHOW = 5,

 

            /// <summary>

            /// SW_MINIMIZE

            /// </summary>

            SW_MINIMIZE = 6,

 

            /// <summary>

            /// SW_SHOWMINNOACTIVE

            /// </summary>

            SW_SHOWMINNOACTIVE = 7,

 

            /// <summary>

            /// SW_SHOWN

            /// </summary>

            SW_SHOWN = 8,

 

            /// <summary>

            /// SW_RESTORE

            /// </summary>

            SW_RESTORE = 9,

 

            /// <summary>

            /// SW_SHOWDEFAULT

            /// </summary>

            SW_SHOWDEFAULT = 10,

 

            /// <summary>

            /// SW_MAX

            /// </summary>

            SW_MAX = 10

        }

 

        #endregion

        #region WTS 연결 상태 클래스 - WTS_CONNECTSTATE_CLASS

 

        /// <summary>

        /// WTS 연결 상태 클래스

        /// </summary>

        private enum WTS_CONNECTSTATE_CLASS

        {

            /// <summary>

            /// WTSActive

            /// </summary>

            WTSActive,

 

            /// <summary>

            /// WTSConnected

            /// </summary>

            WTSConnected,

 

            /// <summary>

            /// WTSConnectQuery

            /// </summary>

            WTSConnectQuery,

 

            /// <summary>

            /// WTSShadow

            /// </summary>

            WTSShadow,

 

            /// <summary>

            /// WTSDisconnected

            /// </summary>

            WTSDisconnected,

 

            /// <summary>

            /// WTSIdle

            /// </summary>

            WTSIdle,

 

            /// <summary>

            /// WTSListen

            /// </summary>

            WTSListen,

 

            /// <summary>

            /// WTSReset

            /// </summary>

            WTSReset,

 

            /// <summary>

            /// WTSDown

            /// </summary>

            WTSDown,

 

            /// <summary>

            /// WTSInit

            /// </summary>

            WTSInit

        }

 

        #endregion

        #region 보안 가장 레벨 - SECURITY_IMPERSONATION_LEVEL

 

        /// <summary>

        /// 보안 가장 레벨

        /// </summary>

        private enum SECURITY_IMPERSONATION_LEVEL

        {

            /// <summary>

            /// SecurityAnonymous

            /// </summary>

            SecurityAnonymous = 0,

 

            /// <summary>

            /// SecurityIdentification

            /// </summary>

            SecurityIdentification = 1,

 

            /// <summary>

            /// SecurityImpersonation

            /// </summary>

            SecurityImpersonation = 2,

 

            /// <summary>

            /// SecurityDelegation

            /// </summary>

            SecurityDelegation = 3

        }

 

        #endregion

        #region 토큰 타입 - TOKEN_TYPE

 

        /// <summary>

        /// 토큰 타입

        /// </summary>

        private enum TOKEN_TYPE

        {

            /// <summary>

            /// TokenPrimary

            /// </summary>

            TokenPrimary = 1,

 

            /// <summary>

            /// TokenImpersonation

            /// </summary>

            TokenImpersonation = 2

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Structure

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 프로세스 정보 - PROCESS_INFORMATION

 

        /// <summary>

        /// 프로세스 정보

        /// </summary>

        [StructLayout(LayoutKind.Sequential)]

        public struct PROCESS_INFORMATION

        {

            //////////////////////////////////////////////////////////////////////////////////////////////////// Field

            ////////////////////////////////////////////////////////////////////////////////////////// Public

 

            #region Field

 

            /// <summary>

            /// 프로세스 핸들

            /// </summary>

            public IntPtr ProcessHandle;

 

            /// <summary>

            /// 스레드 핸들

            /// </summary>

            public IntPtr ThreadHandle;

 

            /// <summary>

            /// 프로세스 ID

            /// </summary>

            public uint ProcessID;

 

            /// <summary>

            /// 스레드 ID

            /// </summary>

            public uint ThreadID;

 

            #endregion

        }

 

        #endregion

        #region 시작 정보 - STARTUPINFO

 

        /// <summary>

        /// 시작 정보

        /// </summary>

        [StructLayout(LayoutKind.Sequential)]

        private struct STARTUPINFO

        {

            //////////////////////////////////////////////////////////////////////////////////////////////////// Field

            ////////////////////////////////////////////////////////////////////////////////////////// Public

 

            #region Field

 

            /// <summary>

            /// 바이트 카운트

            /// </summary>

            public int ByteCount;

 

            /// <summary>

            /// 예약 문자열

            /// </summary>

            public string ReservedString;

 

            /// <summary>

            /// 데스크톱

            /// </summary>

            public string Desktop;

 

            /// <summary>

            /// 제목

            /// </summary>

            public string Title;

 

            /// <summary>

            /// X

            /// </summary>

            public uint X;

 

            /// <summary>

            ///

            /// </summary>

            public uint Y;

 

            /// <summary>

            /// X 크기

            /// </summary>

            public uint XSize;

 

            /// <summary>

            /// Y 크기

            /// </summary>

            public uint YSize;

 

            /// <summary>

            /// X 카운트 (문자 단위)

            /// </summary>

            public uint XCountCharacter;

 

            /// <summary>

            /// Y 카운트 (문자 단위)

            /// </summary>

            public uint YCountCharacter;

 

            /// <summary>

            /// 채우기 어트리뷰트

            /// </summary>

            public uint FillAttribute;

 

            /// <summary>

            /// 플래그

            /// </summary>

            public uint Flag;

 

            /// <summary>

            /// 윈도우 표시

            /// </summary>

            public short ShowWindow;

 

            /// <summary>

            /// 예약 핸들 바이트 카운트

            /// </summary>

            public short ByteCountReservedHandle;

 

            /// <summary>

            /// 예약 핸들

            /// </summary>

            public IntPtr ReservedHandle;

 

            /// <summary>

            /// 표준 입력 핸들

            /// </summary>

            public IntPtr StandardInputHandle;

 

            /// <summary>

            /// 표준 출력 핸들

            /// </summary>

            public IntPtr StandardOutputHandle;

 

            /// <summary>

            /// 표준 에러 핸들

            /// </summary>

            public IntPtr StandardErrorHandle;

 

            #endregion

        }

 

        #endregion

        #region WTS 세션 정보 - WTS_SESSION_INFO

 

        /// <summary>

        /// WTS 세션 정보

        /// </summary>

        [StructLayout(LayoutKind.Sequential)]

        private struct WTS_SESSION_INFO

        {

            //////////////////////////////////////////////////////////////////////////////////////////////////// Field

            ////////////////////////////////////////////////////////////////////////////////////////// Public

    

            #region Field

 

            /// <summary>

            /// 세션 ID

            /// </summary>

            public readonly uint SessionID;

 

            /// <summary>

            /// WIN 스테이션명

            /// </summary>

            [MarshalAs(UnmanagedType.LPStr)]

            public readonly string WinStationName;

 

            /// <summary>

            /// 상태

            /// </summary>

            public readonly WTS_CONNECTSTATE_CLASS State;

 

            #endregion

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Import

        ////////////////////////////////////////////////////////////////////////////////////////// Static

 

        #region 사용자로 프로세스 생성하기 - CreateProcessAsUser(tokenHandle, applicationName, commandLine, processAttributeHandle,

            threadAttributeHandle, inheritHandle, creationFlag, environmentHandle, currentDirectoryPath, startupInfo, processInformation)

 

        /// <summary>

        /// 사용자로 프로세스 생성하기

        /// </summary>

        /// <param name="tokenHandle">토큰 핸들</param>

        /// <param name="applicationName">애플리케이션명</param>

        /// <param name="commandLine">명령줄</param>

        /// <param name="processAttributeHandle">프로세스 어트리뷰트 핸들</param>

        /// <param name="threadAttributeHandle">스레드 어트리뷰트 핸들</param>

        /// <param name="inheritHandle">상속 핸들</param>

        /// <param name="creationFlag">생성 플래그</param>

        /// <param name="environmentHandle">환경 핸들</param>

        /// <param name="currentDirectoryPath">현재 디렉토리 경로</param>

        /// <param name="startupInfo">시작 정보</param>

        /// <param name="processInformation">프로세스 정보</param>

        /// <returns>처리 결과</returns>

        [

            DllImport

            (

                "advapi32.dll",

                EntryPoint        = "CreateProcessAsUser",

                SetLastError      = true,

                CharSet           = CharSet.Ansi,

                CallingConvention = CallingConvention.StdCall

            )

        ]

        private static extern bool CreateProcessAsUser

        (

            IntPtr                  tokenHandle,

            string                  applicationName,

            string                  commandLine,

            IntPtr                  processAttributeHandle,

            IntPtr                  threadAttributeHandle,

            bool                    inheritHandle,

            uint                    creationFlag,

            IntPtr                  environmentHandle,

            string                  currentDirectoryPath,

            ref STARTUPINFO         startupInfo,

            out PROCESS_INFORMATION processInformation

        );

 

        #endregion

        #region 토큰 복제하기 (확장) - DuplicateTokenEx(existingTokenHandle, desiredAccess, threadAttributeHandle,

            tokenType, impersonationLevel, duplicateTokenHandle)

 

        /// <summary>

        /// 토큰 복제하기 (확장)

        /// </summary>

        /// <param name="existingTokenHandle">기존 토클 핸들</param>

        /// <param name="desiredAccess">희망 액세스</param>

        /// <param name="threadAttributeHandle">스레드 어트리뷰트 핸들</param>

        /// <param name="tokenType">토큰 타입</param>

        /// <param name="impersonationLevel">가장 레벨</param>

        /// <param name="duplicateTokenHandle">복제 토큰 핸들</param>

        /// <returns>처리 결과</returns>

        [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]

        private static extern bool DuplicateTokenEx

        (

            IntPtr     existingTokenHandle,

            uint       desiredAccess,

            IntPtr     threadAttributeHandle,

            int        tokenType,

            int        impersonationLevel,

            ref IntPtr duplicateTokenHandle

        );

 

        #endregion

        #region 환경 블럭 생성하기 - CreateEnvironmentBlock(environmentHandle, tokenHandle, inherit)

 

        /// <summary>

        /// 환경 블럭 생성하기

        /// </summary>

        /// <param name="environmentHandle">환경 핸들</param>

        /// <param name="tokenHandle">토큰 핸들</param>

        /// <param name="inherit">상속 여부</param>

        /// <returns>처리 결과</returns>

        [DllImport("userenv.dll", SetLastError = true)]

        private static extern bool CreateEnvironmentBlock(ref IntPtr environmentHandle, IntPtr tokenHandle, bool inherit);

 

        #endregion

        #region 환경 블럭 제거하기 - DestroyEnvironmentBlock(environmentHandle)

 

        /// <summary>

        /// 환경 블럭 제거하기

        /// </summary>

        /// <param name="environmentHandle">환경 핸들</param>

        /// <returns>처리 결과</returns>

        [DllImport("userenv.dll", SetLastError = true)]

        [return: MarshalAs(UnmanagedType.Bool)]

        private static extern bool DestroyEnvironmentBlock(IntPtr environmentHandle);

 

        #endregion

        #region 핸들 닫기 - CloseHandle(snapshotHandle)

 

        /// <summary>

        /// 핸들 닫기

        /// </summary>

        /// <param name="snapshotHandle">스냅샷 핸들</param>

        /// <returns>처리 결과</returns>

        [DllImport("kernel32.dll", SetLastError = true)]

        private static extern bool CloseHandle(IntPtr snapshotHandle);

 

        #endregion

        #region WTS 활성 콘솔 세션 ID 구하기 - WTSGetActiveConsoleSessionId()

 

        /// <summary>

        /// WTS 활성 콘솔 세션 ID 구하기

        /// </summary>

        /// <returns>활성 콘솔 세션 ID</returns>

        [DllImport("kernel32.dll")]

        private static extern uint WTSGetActiveConsoleSessionId();

 

        #endregion

        #region WTS 사용자 토큰 질의하기 - WTSQueryUserToken(sessionID, tokenHandle)

 

        /// <summary>

        /// WTS 사용자 토큰 질의하기

        /// </summary>

        /// <param name="sessionID">세션 ID</param>

        /// <param name="tokenHandle">토큰 핸들</param>

        /// <returns>처리 결과</returns>

        [DllImport("wtsapi32.dll")]

        private static extern uint WTSQueryUserToken(uint sessionID, ref IntPtr tokenHandle);

 

        #endregion

        #region WTS 세션 열거하기 - WTSEnumerateSessions(serverHandle, reserved, version, sessionInfoHandle, count)

 

        /// <summary>

        /// WTS 세션 열거하기

        /// </summary>

        /// <param name="serverHandle">서버 핸들</param>

        /// <param name="reserved">예약</param>

        /// <param name="version">버전</param>

        /// <param name="sessionInfoHandle">세션 정보 핸들</param>

        /// <param name="count">카운트</param>

        /// <returns>처리 결과</returns>

        [DllImport("wtsapi32.dll", SetLastError = true)]

        private static extern int WTSEnumerateSessions

        (

            IntPtr     serverHandle,

            int        reserved,

            int        version,

            ref IntPtr sessionInfoHandle,

            ref int    count

        );

 

        #endregion

        #region WTF 메모리 해제하기 - WTSFreeMemory(memoryHandle)

 

        /// <summary>

        /// WTF 메모리 해제하기

        /// </summary>

        /// <param name="memoryHandle">메모리 핸들</param>

        [DllImport("wtsapi32.dll")]

        private static extern void WTSFreeMemory(IntPtr memoryHandle);

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// WTS_CURRENT_SERVER_HANDLE

        /// </summary>

        private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// CREATE_UNICODE_ENVIRONMENT

        /// </summary>

        private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;

 

        /// <summary>

        /// CREATE_NO_WINDOW

        /// </summary>

        private const int CREATE_NO_WINDOW = 0x08000000;

 

        /// <summary>

        /// CREATE_NEW_CONSOLE

        /// </summary>

        private const int CREATE_NEW_CONSOLE = 0x00000010;

 

        /// <summary>

        /// INVALID_SESSION_ID

        /// </summary>

        private const uint INVALID_SESSION_ID = 0xffffffff;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 사용자 토큰 구하기 - GetSessionUserToken(userTokenHandle)

 

        /// <summary>

        /// 사용자 토큰 구하기

        /// </summary>

        /// <param name="userTokenHandle">사용자 토큰 핸들</param>

        /// <returns>처리 결과</returns>

        public static bool GetSessionUserToken(ref IntPtr userTokenHandle)

        {

            bool   result                   = false;

            IntPtr impersonationTokenHandle = IntPtr.Zero;

            uint   activeSessionID          = INVALID_SESSION_ID;

            IntPtr sessionInfoHandle        = IntPtr.Zero;

            int    sessionCount             = 0;

 

            if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref sessionInfoHandle, ref sessionCount) != 0)

            {

                int arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));

 

                IntPtr currentSessionInfoHandle = sessionInfoHandle;

 

                for(int i = 0; i < sessionCount; i++)

                {

                    WTS_SESSION_INFO sessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure

                    (

                        currentSessionInfoHandle,

                        typeof(WTS_SESSION_INFO)

                    );

 

                    currentSessionInfoHandle += arrayElementSize;

 

                    if(sessionInfo.State == WTS_CONNECTSTATE_CLASS.WTSActive)

                    {

                        activeSessionID = sessionInfo.SessionID;

 

                        break;

                    }

                }

 

                WTSFreeMemory(sessionInfoHandle);

            }

 

            if(activeSessionID == INVALID_SESSION_ID)

            {

                activeSessionID = WTSGetActiveConsoleSessionId();

            }

 

            if(WTSQueryUserToken(activeSessionID, ref impersonationTokenHandle) != 0)

            {

                result = DuplicateTokenEx

                (

                    impersonationTokenHandle,

                    0,

                    IntPtr.Zero,

                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,

                    (int)TOKEN_TYPE.TokenPrimary,

                    ref userTokenHandle

                );

 

                CloseHandle(impersonationTokenHandle);

            }

 

            return result;

        }

 

        #endregion

        #region 현재 사용자로 프로세스 실행하기 - ExecuteProcessAsCurrentUser(applicationPath, processInformation,

            commandLine, workingDirectoryPath, visible)

 

        /// <summary>

        /// 현재 사용자로 프로세스 실행하기

        /// </summary>

        /// <param name="applicationPath">애플리케이션 경로</param>

        /// <param name="processInformation">프로세스 정보</param>

        /// <param name="commandLine">명령줄</param>

        /// <param name="workingDirectoryPath">작업 디렉토리 경로</param>

        /// <param name="visible">표시 여부</param>

        /// <returns>처리 결과</returns>

        public static bool ExecuteProcessAsCurrentUser

        (

            string                  applicationPath,

            out PROCESS_INFORMATION processInformation,

            string                  commandLine          = null,

            string                  workingDirectoryPath = null,

            bool                    visible              = true

        )

        {

            IntPtr userTokenHandle  = IntPtr.Zero;

            STARTUPINFO startupInfo = new STARTUPINFO();

 

            startupInfo.ByteCount  = Marshal.SizeOf(typeof(STARTUPINFO));

            startupInfo.ShowWindow = (short)(visible ? ShowWindowType.SW_SHOW : ShowWindowType.SW_HIDE);

            startupInfo.Desktop    = "winsta0\\default";

 

            processInformation = new PROCESS_INFORMATION();

 

            IntPtr environmentHandle = IntPtr.Zero;

            int    errorCode;

 

            try

            {

                if(!GetSessionUserToken(ref userTokenHandle))

                {

                    throw new Exception("StartProcessAsCurrentUser : GetSessionUserToken failed.");

                }

 

                uint creationFlag = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);

 

                if(!CreateEnvironmentBlock(ref environmentHandle, userTokenHandle, false))

                {

                    throw new Exception("StartProcessAsCurrentUser : CreateEnvironmentBlock failed.");

                }

 

                if

                (

                    !CreateProcessAsUser

                    (

                        userTokenHandle,

                        applicationPath,

                        commandLine,

                        IntPtr.Zero,

                        IntPtr.Zero,

                        false,

                        creationFlag,

                        environmentHandle,

                        workingDirectoryPath,

                        ref startupInfo,

                        out processInformation

                    )

                )

                {

                    errorCode = Marshal.GetLastWin32Error();

 

                    string errorMessage = string.Format

                    (

                        "StartProcessAsCurrentUser : CreateProcessAsUser failed. Error Code : {0}, applicationPath : {1}, commandLine : {2}",

                        errorCode,

                        applicationPath,

                        commandLine

                    );

 

                    throw new Exception(errorMessage);

                }

            }

            finally

            {

                CloseHandle(userTokenHandle);

 

                if(environmentHandle != IntPtr.Zero)

                {

                    DestroyEnvironmentBlock(environmentHandle);

                }

 

                CloseHandle(processInformation.ThreadHandle);

                CloseHandle(processInformation.ProcessHandle);

            }

 

            return true;

        }

 

        #endregion

        #region 프로세스 실행하기 - ExecuteProcess(filePath)

 

        /// <summary>

        /// 프로세스 실행하기

        /// </summary>

        /// <param name="filePath">파일 경로</param>

        /// <returns>프로세스 핸들</returns>

        public static int ExecuteProcess(string filePath)

        {

            if(string.IsNullOrWhiteSpace(filePath))

            {

                return 0;

            }

 

            if(!File.Exists(filePath))

            {

                return 0;

            }

 

            try

            {

                if(!Environment.UserInteractive)

                {

                    if(ProcessHelper.ExecuteProcessAsCurrentUser(filePath, out ProcessHelper.PROCESS_INFORMATION processInformation))

                    {

                        return (int)processInformation.ProcessID;

                    }

                }

                else

                {

                    ProcessStartInfo processStartInfo = new ProcessStartInfo()

                    {

                        FileName        = filePath,

                        WindowStyle     = ProcessWindowStyle.Normal,

                        UseShellExecute = false

                    };

 

                    Process process = Process.Start(processStartInfo);

 

                    return process.Id;

                }

            }

            catch

            {

            }

 

            return 0;

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

※ 윈도우즈 서비스 실행시 현재 사용자 계정으로 가장해서 실행할 수 있다.

728x90
반응형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요