본문 바로가기
VisualStudio.C++.C#/코딩팁,함수활용,단편

외부프로그램 실행시키기. CreateProcess, ShellExecute, WinExec

by 리치굿맨 2016. 1. 28.

 

 

 

개요

  외부프로그램 실행시키는 함수 3개(CreateProcess, ShellExecute,WinExec) 비교 및 CreateProcess 사용법 상세. 


비교.
WinExec 
- window3.1 때부터 제공된 함수이며 하위 호환성 때문에 아직도 남아있는것 MS에서는 이 함수 대신 CreateProcess 사용 권장.
- UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow) 인자1:실행할 프로그램 커맨드라인. 인자2:실행시 윈도우 상태 보이기 안보이기등 지정.


CreateProcess
- 실행옵션 미세 설정가능. 실행시킬 때 인자전달 가능.
- 반환값 : 대상프로그램이 실행되면 0 아닌값 , 실행되지 않으면 0반환.
- 대상프로그램의 실행여부,실행실패원인,종료여부 확인가능.


더보기


CreateProcess()의 프로토 타입.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
BOOL CreateProcess(
 
LPCTSTR lpApplicationName,       // 실행파일 모듈의 이름에 대한 포인터. 
LPTSTR lpCommandLine,             // 커맨드 문자열에 대한 포인터
LPSECURITY_ATTRIBUTES lpPA,  // 프로세스 보안 속성 구조체 포인터
LPSECURITY_ATTRIBUTES lpTA,  // 스레드 보호속성 구조체 포인터
BOOL bInheritHandles,                // 핸들 상속 여부 플래그, 상속보호 플래그 핸들 플래그.
DWORD dwCreationFlags,            // 생성 플래그, 프로세스 생성 플래그.
LPVOID lpEnvironment,                // 환경 블록에 대한 포인터, 프로세스가 실행될 환경변수.
LPCTSTR lpCurrentDirectory,        // 현재 디렉토리, 현재작업 디렉토리.
LPSTARTUPINFO lpStartupInfo,     // STARTUPINFO 포인터. 실행될 프로그램의  윈도우 관련 설정에 해당함.
LPPROCESS_INFORMATION lpPI  // PROCESS_INFORMATION 포인터
);
 




반환값 :   0 = 외부 프로그램이 실행되지 않음. 0아닌값 : 외부프로그램이 실행됨.
반환값 0이어서 실패한 경우 에러정보 볼려면 GetLastErroe를 호출하라.


이 함수는 대상 프로세스의 실행과정 finish 되기 전에 리턴된다. 만일, 실행시킨 프로세스가 실행 실패한다면 프로세스가 terminated될 수있다. CreateProcess 호출하여 리턴된 이후, 실행시킨 프로세스의 termination status를 확보할려면 GetExitCodeProcess를 호출하라.




인자


lpApplicationName


실행시킬 프로그램 이름.  찾기순서: CreateProcess 함수를 호출한 프로그램이 있는 폴더, 현재폴더, 윈도우폴더, 윈도우시스템폴더, PATH에 설정된 플더순서로 찾기함. 실행파일 정보를 인자 lpCommandLine  으로 입력하는 경우엔 본 인자엔 NULL 기록하면됨. 


lpCommandLine


실행시킬 커맨드 라인.   최대 32,768 문자까지 가능, lpApplicationName  으로 정보 전달시 이것은 NULL로 해도됨.


MSDN도움말 중에 유용한것만  그대로도 가져온다.
lpApplicationName, lpCommandLine  2개 모두 NULL이 아닌 경우, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line.


If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:
  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.
The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.




lpStartupInfo


STARTUPINFO 에는 프로세스를 실행시킬때 시작 정보를 담는 구조체이다. 
구조체멤버를 보면 사이즈 라든가 ..윈도우의 Enable상태 등등 여러 정보가 있고, 이를 사용자가 설정가능하다.

필요시 STARTUPINFO 멤버값을 설정하여 프로세스가 다른 모습으로 실행될 수 있다.  멤버설정없이 프로세스 호출하면 해당프로세스의 셋팅값으로 생성된다. 보통은 별도로 설정할 일이 없음.



lpPI


프로세스 정보를 반환해주기 위한 구조체의 포인터.  프로그램이 성공적으로 실행되면 실행된 프로세스에 대한 정보를 PROCESS_INFORMATION 구조체 형태로 넘겨받을 수 있다. 이를 이용하여 프로세스를 제어할 수 있다.


PROCESS_INFORMATION 구조체의 멤버.


HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;


hProcess : 실행된 프로그램의 프로세스 핸들. 이를 이용하여 프로세스를 제어가능하다. 예로,TerminateProcess 함수를 이용하여 새로 생성시킨 프로세스를 종료시킬 수 있다.  WaitForSingleObject(pi.hProcess,INFINITE) 이용하여 프로세스 종료완료 확인가능.


hThread : 실행된 프로그램의 주 스레드 핸들.


dwProcessId : 프로세스 아이디.


dwThreadId : 스레드 아이디.






==============================================================================================
아래는 MSDN 도움말.
CreateProcess


Creates a new process and its primary thread. The new process runs in the security context of the calling process.
If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation token. To run the new process in the security context of the user represented by the impersonation token, use the CreateProcessAsUser or CreateProcessWithLogonW function.

Syntax

C++
Copy
BOOL WINAPI CreateProcess( _In_opt_    LPCTSTR               lpApplicationName, _Inout_opt_ LPTSTR                lpCommandLine, _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_        BOOL                  bInheritHandles, _In_        DWORD                 dwCreationFlags, _In_opt_    LPVOID                lpEnvironment, _In_opt_    LPCTSTR               lpCurrentDirectory, _In_        LPSTARTUPINFO         lpStartupInfo, _Out_       LPPROCESS_INFORMATION lpProcessInformation );

Parameters

lpApplicationName [in, optional]
The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path. This parameter must include the file name extension; no default extension is assumed.
The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:
c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe
If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments.
To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
lpCommandLine [in, out, optional]
The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:
  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.
The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.
lpProcessAttributes [in, optional]
A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new process object can be inherited by child processes. If lpProcessAttributes is NULL, the handle cannot be inherited.
The lpSecurityDescriptor member of the structure specifies a security descriptor for the new process. If lpProcessAttributes is NULL or lpSecurityDescriptor is NULL, the process gets a default security descriptor. The ACLs in the default security descriptor for a process come from the primary token of the creator.
Windows XP:  The ACLs in the default security descriptor for a process come from the primary or impersonation token of the creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
lpThreadAttributes [in, optional]
A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new thread object can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
The lpSecurityDescriptor member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is NULL or lpSecurityDescriptor is NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the process token.
Windows XP:  The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
bInheritHandles [in]
If this parameter TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE, the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
dwCreationFlags [in]
The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process.
lpEnvironment [in, optional]
A pointer to the environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.
An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:
name=value\0
Because the equal sign is used as a separator, it must not be used in the name of an environment variable.
An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT. If this parameter is NULL and the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
The ANSI version of this function, CreateProcessA fails if the total size of the environment block for the process exceeds 32,767 characters.
Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
lpCurrentDirectory [in, optional]
The full path to the current directory for the process. The string can also specify a UNC path.
If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
lpStartupInfo [in]
A pointer to a STARTUPINFO or STARTUPINFOEX structure.
To set extended attributes, use a STARTUPINFOEX structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter.
Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.
Important  The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle values. These fields are copied unchanged to the child process without validation, even when the dwFlags member specifies STARTF_USESTDHANDLES. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier runtime verification tool to detect invalid handles.
 
lpProcessInformation [out]
A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.
Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.

Return value

If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.

Remarks

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.
The name of the executable in the command line that the operating system provides to a process is not necessarily identical to that in the command line that the calling process gives to the CreateProcess function. The operating system may prepend a fully qualified path to an executable name that is provided without a fully qualified path.
The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.
The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.
A parent process can directly alter the environment variables of a child process during process creation. This is the only situation when a process can directly change the environment settings of another process. For more information, see Changing Environment Variables.
If an application provides an environment block, the current directory information of the system drives is not automatically propagated to the new process. For example, there is an environment variable named =C: whose value is the current directory on drive C. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create these environment variable strings, sort them alphabetically (because the system uses a sorted environment), and put them into the environment block. Typically, they will go at the front of the environment block, due to the environment block sort order.
One way to obtain the current directory information for a drive X is to make the following call: GetFullPathName("X:", ...). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process.
When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has CTRL+C disabled. This lets shells handle CTRL+C themselves, and selectively pass that signal on to sub-processes. CTRL+BREAK is not disabled, and may be used to interrupt the process/process group.

Security Remarks

The first parameter, lpApplicationName, can be NULL, in which case the executable name must be in the white space–delimited string pointed to by lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".
 
Copy
LPTSTR szCmdline = _tcsdup(TEXT("C:\\Program Files\\MyApp -L -S")); CreateProcess(NULL, szCmdline, /* ... */);
If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls CreateProcess using the Program Files directory will run this application instead of the intended application.
To avoid this problem, do not pass NULL for lpApplicationName. If you do pass NULL for lpApplicationName, use quotation marks around the executable path in lpCommandLine, as shown in the example below.
 
Copy
LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\" -L -S")); CreateProcess(NULL, szCmdline, /*...*/);

Examples

For an example, see Creating Processes.

Requirements

Minimum supported client Windows XP [desktop apps only]
Minimum supported server Windows Server 2003 [desktop apps only]
Header
WinBase.h on Windows XP, Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008, and Windows Server 2008 R2 (include Windows.h);
Processthreadsapi.h on Windows 8 and Windows Server 2012
Library
Kernel32.lib
DLL
Kernel32.dll
Unicode and ANSI names CreateProcessW (Unicode) and CreateProcessA (ANSI)

See also

CloseHandle
CreateProcessAsUser
CreateProcessWithLogonW
ExitProcess
GetCommandLine
GetEnvironmentStrings
GetExitCodeProcess
GetFullPathName
GetStartupInfo
OpenProcess
Process and Thread Functions
PROCESS_INFORMATION
Processes
SECURITY_ATTRIBUTES
SetErrorMode
STARTUPINFO
STARTUPINFOEX
TerminateProcess
WaitForInputIdle




from MSDN.


ShellExecute, ShellExecuteEx
- exe 파일 을 실행시키는것외에 일반파일도 인자로 전달하여 인쇄, 탐색기 열기가능.
- 실행시킬 프로그램과 연결된 파일지정 가능. 예. txt 파일을 메모장으로 열기.
- 내부적으로는 CreateProcess 이용함.

   

 

ShellExecute 상세 . from MS

 

ShellExecuteA function (shellapi.h) - Win32 apps

Performs an operation on a specified file.

docs.microsoft.com

 

 

 

 

 

1. CreateProcess 이용 외부 프로그램 실행.

 
 
기본 사용법.
인자들이 많아서 세부조절이 가능하나, 최소한의 인자를 사용하여 notepad.exe 를 실행시키기 위해서는 아래 코드면 된다.
 
1
2
3
4
5
6
7
8
STARTUPINFO StartupInfo = {0};
 
StartupInfo.cb = sizeof(STARTUPINFO); 
 
PROCESS_INFORMATION ProcessInfo;
 
::CreateProcess(NULL, "notepad.exe", NULL,NULL, FALSE, 0,NULL,NULL, &StartupInfo, &ProcessInfo);
 
 
info tip. - unicode 관련.


VS2010 에서 생성된 프로젝트는 기본 문자인코딩이 unicode  로 되어있다. (프로젝트 속성창에서 볼수있고, 변경도 가능하다)


unicode로 되어있는 경우, 함수를 CreateProcess 를 호출해도 실제로 작동되는 코드는 CreateProcessW 가 호출된다.  
CreateProcessW 함수의 특징은 unicode 스타일의 인자 변수형으로 되어있음이다. 예로, lpCommandLine  자료형이 LPTSTR 이 아닌, LPWSTR (= WCHAR* 와 같은거임) 이다.
그럼 변수선언을 LPWSTR 로 해서 사용해도 되는데, 나중에 프로젝트 설정을 unicode 인코딩 속성을 멀티바이트 문자열로 변경하면 코드 수정해야하므로 귀찮다. 이럴때 사용하기 좋은 것이 TCHAR 자료형이다. 프로젝트의 문자열 인코딩 설정이 뭘로 되어있든 정상컴파일되고 정상동작된다.
 
   

MS 사 제공 예제 코드. 

 

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void _tmain( int argc, TCHAR *argv[] )
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    if( argc != 2 )
    {
        printf("Usage: %s [cmdline]\n", argv[0]);
        return;
    }

    // Start the child process. 
    if( !CreateProcess( NULL,   // No module name (use command line)
        argv[1],        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        printf( "CreateProcess failed (%d).\n", GetLastError() );
        return;
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}

from : 프로세스 만들기 - Win32 apps | Microsoft Docs

 

 

 

 

 본 글이 포함된 상위 정리 장소.


 Visual Studio/VC++/C/C# 활용정리 -> http://igotit.tistory.com/11

 

 

 


첫 등록 : 2016.0128

최종 수정 : 2021.09.12

단축 주소 : https://igotit.tistory.com/627


 

 

 

 

댓글0


.    
현물 |선물 인버스 |선물 USDT     현물 | 선물 USDT |봇제작툴/카피트레이딩     현물 |선물 인버스 |선물 USDT     .