Detailed explanation of CreateProcess function

 

There are detailed explanations in Windows programming five

CreateProcess
description:
WIN32API function CreateProcess is used to create a new process and its main thread, this new process runs the specified executable file.

Function prototype:

  1. BOOL CreateProcess  
  2. (  
  3.     LPCTSTR lpApplicationName,          
  4.     LPTSTR lpCommandLine,          
  5.     LPSECURITY_ATTRIBUTES lpProcessAttributes。  
  6.     LPSECURITY_ATTRIBUTES lpThreadAttributes,          
  7.     BOOL bInheritHandles,          
  8.     DWORD dwCreationFlags,  
  9.     LPVOID lpEnvironment,          
  10.     LPCTSTR lpCurrentDirectory,          
  11.     LPSTARTUPINFO lpStartupInfo,          
  12.     LPPROCESS_INFORMATION lpProcessInformation   
  13. );  
A thread calls it to first create a process kernel object, which is used to manage the new process, then the system creates the virtual address space for the new process and loads the executable (and DLL) code and data into this address space, then the system creates a thread kernel object for the main thread of the new process.

 

First explain lpApplicationName and lpCommandLine

lpApplicationName and lpCommandLine respectively point to the name of the executable file to be used by the new process, and the command line string to pass to the new process. lpCommandLine is of type LPTSTR, because internally, CreateProcess actually modifies what we pass to him. The command line string, of course it will restore the string before it returns, so code like this is wrong:

  1. STARTUPINFO si = { sizeof (si)};  
  2.     PROCESS_INFORMATION pi ;  
  3.     CreateProcess(NULL,TEXT("NOTEPAD"),NULL,NULL,  
  4.         FALSE,0,NULL,NULL,&si,&pi) ;  
The solution to this bug is to copy the constant string into a temporary buffer, like this:
  1. STARTUPINFO si = { sizeof (si)};  
  2.     PROCESS_INFORMATION pi ;  
  3.     TCHAR szCommandLine[] = TEXT("NOTEPAD") ;  
  4.     CreateProcess(NULL,szCommandLine,NULL,NULL,  
  5.         FALSE,0,NULL,NULL,&si,&pi) ;  

So, expect Microsoft to fix it in a future version of windows and create a temporary copy of the string itself, let's free it

 

Two states:

1: lpApplicationName is NULL, (99% are set to NULL)

    In this case, the name of the executable module must be at the beginning of the lpCommandLine parameter and separated from the following characters by a space character. When CreateProcess parses the lpCommandLine string, it checks the first token in the string. , and assuming this tag is the name of the executable we want to run, if the executable's name has no extension, it defaults to .exe, and if the filename doesn't contain a full path, CreateProcess will also run in the following order Search for executables:

(1) The directory where the calling process .exe file is located

(2) The current directory of the calling process

(3) Windows system directory, that is, the System32 subfolder returned by GetSystemDirectory

(4) windows directory

(5) Directories listed in the PATH environment variable

2: lpApplicationName is not NULL

   In this case, the file extension must be specified, the system will not automatically assume the extension like 1, and if the file name does not contain a full path, CreateProcess will only look for the executable in the current directory, not in other any directory lookup.

 

Once the system finds the executable, it creates a new process and maps the executable's code and data into the address space of the new process, then starts the routine, C/C++ will put the first file after the executable name The address of the actual parameter is passed to the pszCmdLine parameter of (w)WinMain

 

Explain again lpProcessAttributes and lpThreadAttributes

 

In order to create a new process, the system must create a process kernel object and the thread kernel object of the main thread of the new process. These two parameters identify the security descriptors of these two kernel objects.

 

Needless to say bInheritHandles, set the inheritance of the handle description table of the parent and child processes

 

dwCreationFlags identifies flags that affect how new processes are created

 

Value: CREATE_DEFAULT_ERROR_MODE
Meaning: The new process does not inherit the error mode of the calling process. The CreateProcess function assigns the new process the current default error mode as an alternative. An application can call the SetErrorMode function to set the current default error mode.
This flag is useful for multithreaded shells that run without hardware errors.
For the CreateProcess function, the default behavior is to inherit the caller's error mode for new processes. Set this flag to change the default handling.

Value: CREATE_NEW_CONSOLE
Meaning: The new process will use a new console instead of inheriting the console of the parent process. This flag cannot be used with the DETACHED_PROCESS flag.

Value: CREATE_NEW_PROCESS_GROUP
Meaning: The new process will be the root process of a process tree. All processes in the process tree are children of the root process. The user ID of the new process tree is the same as the ID of this process, as returned by the lpProcessInformation parameter. Process trees often use the GenerateConsoleCtrlEvent function to allow sending the CTRL+C or CTRL+BREAK signal to a group of console processes.

Value: CREATE_SEPARATE_WOW_VDM
Meaning: (Windows NT only) This flag is only valid when running a 16-bit Windows application. If set, the new process will run in a private virtual DOS machine (VDM). Also, by default all 16-bit Windows applications run as threads in the same shared VDM. The advantage of running a 16-bit program alone is that the crash of one application only ends the operation of this VDM; other programs running in a different VDM will continue to run normally. Likewise, 16-bit Windows applications running in different VDMs have different input queues, which means that if an application becomes temporarily unresponsive, applications in separate VDMs can continue to get input.

Value: CREATE_SHARED_WOW_VDM
Meaning: (Windows NT only) This flag is only valid when running a 16-bit Windows application. If the DefaultSeparateVDM option of the Windows section in WIN.INI is set to true, this flag causes the CreateProcess function to override this option and run the new process in the shared virtual DOS machine.

Value: CREATE_SUSPENDED
Meaning: The main thread of the new process will be suspended after creation and will not run until the ResumeThread function is called, so that the parent process can modify the memory in the address space of the child process and change the main thread of the child process. The priority of the thread, or adding it to a job before the process executes any code. After the parent process modifies the child process, it calls ResumeThread to allow the child process to execute code.

Value: CREATE_UNICODE_ENVIRONMENT
Meaning: If set, the environment block specified by the lpEnvironment parameter uses Unicode characters, if empty, the environment block uses ANSI characters.

Value: DEBUG_PROCESS
Meaning: If this flag is set, the calling process will be treated as a debugger, and the new process will be treated as the debugged process. The system notifies the debugger of all debug events that occur in the debugged program.
If you create a process with this flag, only the calling process (the one that called the CreateProcess function) can call the WaitForDebugEvent function.

Value: DEBUG_ONLY_THIS_PROCESS
Meaning: If this flag is not set and the calling process is being debugged, the new process will become another debuggee for the debugger that debugs the calling process. If the calling process is not debugged, no debug-related behavior will occur.

Value: DETACHED_PROCESS
Meaning: For console processes, the new process does not have permission to access the console of the parent process. A new process can create a new console by itself through the AllocConsole function. This flag cannot be used with the CREATE_NEW_CONSOLE flag.

The dwCreationFlags parameter is also used to control the priority class of the new process, which is used to determine the priority of the thread scheduling of this process. If none of the following priority class flags are specified, then the default priority class is NORMAL_PRIORITY_CLASS, unless the process being created is IDLE_PRIORITY_CLASS. The default priority class for child processes in this case is IDLE_PRIORITY_CLASS.
Can be one of the following flags:

Priority: HIGH_PRIORITY_CLASS       
Meaning: Indicates that this process will perform time-critical tasks, so it must be run immediately to ensure correctness. Programs at this priority take precedence over programs at normal or idle priority. An example is the Windows task list, which forgoes system load in order to ensure immediate response when invoked by the user. Make sure you use high priority with caution, as a high-priority CPU-bound application can consume almost all of the CPU's available time.

Priority: IDLE_PRIORITY_CLASS       
Meaning: Indicates that the thread of this process will only run when the system is idle and can be interrupted by any high-priority task. For example a screen saver. The idle priority is inherited by child processes.

Priority: NORMAL_PRIORITY_CLASS       
Meaning: Indicates that this process has no special task scheduling requirements.

Priority: REALTIME_PRIORITY_CLASS       
Meaning: Indicates that this process has the highest priority available. A thread of a process with real-time priority can interrupt the execution of all other process threads, including system processes that are performing important tasks. For example, a real-time process that takes a little longer to execute may cause insufficient disk cache or sluggish mouse response.

 

lpEnvironment:

    Pointer to an environment block for a new process. If this parameter is empty, the new process uses the environment of the calling process.
  An environment block exists within a block of NULL-terminated strings that are also NULL-terminated. Each string is of the form name=value.
  Because the equality flag is used as a delimiter, it cannot be used as a variable name by an environment variable.
  Instead of using an application-supplied environment block, simply leave this parameter empty, and the current directory information on the system drive will not be automatically passed to newly created processes. See the Notes section for a discussion of this situation and how to deal with it.
  Environment blocks can contain Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, then the CREATE_UNICODE_ENVIRONMENT flag of the dwCreationFlags field will be set. This flag will be cleared if the block contains ANSI characters.
  Note that an ANSI environment block is terminated by two zero bytes: one is the end of the string, and the other is used to end the block. A Unicode environment block is terminated by four zero bytes: two represent the end of the string, and the other two are used to end the block.

 

lpCurrentDirectory:

    Points to a NULL-terminated string that specifies the working path of the child process. This string must be an absolute path containing the drive name. If this parameter is NULL, the new process will use the same drive and directory as the calling process. This option is the main condition for a shell that needs to launch applications that start and specify their drive and working directory.

 

lpStartupInfo:

  1. typedef struct _STARTUPINFO   
  2. {   
  3. DWORD cb;  
  4. LPTSTR lpReserved;    
  5. LPTSTR lpDesktop;   
  6. LPTSTR lpTitle;    
  7. DWORD dwX;    
  8. DWORD TWY;    
  9. DWORD dwXSize;  
  10. DWORD dwYSize;    
  11. DWORD dwXCountChars;    
  12. DWORD dwYCountChars;    
  13. DWORD dwFillAttribute;    
  14. DWORD dwFlags;    
  15. WORD wShowWindow;    
  16. WORD cbReserved2;    
  17. LPBYTE lpReserved2;    
  18. HANDLE hStdInput;    
  19. HANDLE hStdOutput;    
  20. HANDLE hStdError;  
  21. } STARTUPINFO, * LPSTARTUPINFO;  

Points to a STARTUPINFO structure that determines how the main window of the new process is displayed.

Most applications want the generated application to just use the default value, at least all initialized to 0, and then set the cb member to the size of this structure, if it is not cleared to 0, the new process may fail to create.

Table 4-6 Members of the STARTUPINFO structure

member window, console or both effect
cb both Contains the number of bytes in the STAT UPINFO structure. If Microsoft expands this structure in the future, it can be used as a means of version control. The application must initialize cb to sizeof ( STAT UPINFO )
lpReserved both Reserve. must be initialized to NULL
lpDesktop both The name used to identify the desktop on which the application was launched. If the desktop exists, the new process is associated with the specified desktop. If the desktop does not exist, create a desktop with default properties and use the name given to the new process. If lp Desktop is NULL (which is the most common case), then the process will be associated with the current desktop
lpTitle console Used to set the name of the console window. If lpTitle is NULL, the name of the executable will be used as the window name
dwX
dwY
both The x and y coordinates (in pixels) used to set the position on the screen where the application window should be placed. These two coordinates are only used when the child process creates its first overlapping window with CW_USEDEFAULT as the x parameter of Create Window. For applications that create console windows, these members are used to indicate the upper left corner of the console window
dwXSize both Only dwYsize is used to set the width and length of the application window (in pixels) when the child process creates its first overlapping window using CW_USEDE FAULT as the n Wi dth parameter of Create Window , use these values. If an application creates a console window, these members will be used to indicate the width of the console window
dwXCountChars
dwYCountChars
console Used to set the width and height (in characters) of the subapplication's console window
dwFillAttribute console Used to set the text and background colors used by the sub-application's console window
dwFlags both See description in next paragraph and Tables 4 - 7
wShowWindow window Used to set how the application's first overlapping window should appear if the child application's initial call to ShowWindow passes SW_SHOWDEFAULT as the nCmdShow parameter. This member can be any of the SW_* identifiers normally used in the Show Window function
cbReserved2 both Reserve. must be initialized to 0
lpReserved2 both Reserve. must be initialized to NULL
hStdInput
hStdOutput
hStdError
console A handle to set the buffer for console input and output. By default, h Std I nput is used to identify the keyboard cache, h Std Output and h Std Error are used to identify the console window cache

 

dwFlags包含一组标志,大多数标志都只是告诉CreateProcess函数,STARTUPINFO 中其他成员是否包含有用的信息,或者是否应该忽略一些成员

表4-7 使用标志及含义

 

标志 含义
STARTF_USESIZE 使用d w X S i z e 和d w Y S i z e 成员
STARTF_USESHOWWINDOW 使用w S h o w Wi n d o w 成员
STARTF_USEPOSITION 使用d w X 和d w Y 成员
STARTF_USECOUNTCHARS 使用d w X C o u n t C h a r s 和dwYCount Chars 成员
STARTF_USEFILLATTRIBUTE 使用d w F i l l A t t r i b u t e 成员
STARTF_USESTDHANDLES 使用h S t d I n p u t 、h S t d O u t p u t 和h S t d E r r o r 成员
STARTF_RUN_FULLSCREEN 强制在x 8 6 计算机上运行的控制台应用程序以全屏幕方式启动运行

 

 

另外还有两个标志即STARTF_ORCEONFEEDBACK和STARTFFORCEOFFFEEDBACK,当启动一个新进程时,它们可以用来控制鼠标的光标,由于windows支持真正的多任务抢占式运行方式,因此可以启动一个应用程序,然后在进程初始化时使用另一个程序,为了向用户提供视觉反馈,CreateProcess临时会把系统的光标改成一个新的光标,但

     如果指定了STARTF_ORCEONFEEDBACK,CreateProcess就不会改变光标

   如果指定了STARTFFORCEOFFFEEDBACK,CreateProcess会改变成新的光标,在2秒之后,如果新进程没有执行任何GUI调用,光标还原,如果执行了GUI调用,则在5秒内必须显示窗口,否则光标同样还原,

  

lpStartupInfo

   指向必须指定的PROCESS_INFORMATION结构体

  1. typedef struct _PROCESS_INFORMATION {   
  2.   HANDLE hProcess;   
  3.   HANDLE hThread;   
  4.   DWORD dwProcessId;   
  5.   DWORD dwThreadId;   
  6. } PROCESS_INFORMATION;   

 如前所述,创建新进程可使系统建立一个进程内核对象和一个线程内核对象,在创建进程的时候,系统为每个对象赋予一个初始使用计数值1,然后,在CreateProcess返回之前,该函数打开进程内核对象和线程内核对象,并将每个对象的与进程相关的句柄放_PROCESS_INFORMATION中的hProcess和hThread,当CreateProcess在内部打开这些对象时,每个对象的使用计数就变为2。

 

所以注意必须关闭子进程和它的主线程的句柄,以避免在应用程序运行中泄漏资源,当然当进程终止运行时,系统如自动消除这些泄漏现象,但是,当进程不再需要访问子进程和它的线程时,编写得较好的软件能够显示关闭这些句柄(通过调用CloseHandle函数来关闭),不能关闭这些句柄是开发人员最常犯的错误之一.

 

当进程和线程内核对象创建时,系统都为赋予该对象一个独一无二的,系统范围内的ID号,进程ID和线程ID共享相同的号码池,这意味着进程和线程不可能拥有相同的ID,另外ID不能为0,同样,在CreateProcess返回时,dwProcessId和dwThreadId被填充,ID使你能非常容易识别系统中的进程和线程,一些实用工具(如Task Manager)对ID使用最多,而高效率的应用程序则使用得很少,因于这个原因,大多数应用程序完全忽略ID。

 

如果应用程序使用ID来跟踪进程和线程,必须懂得系统会立即复用进程ID和线程ID,如,一个进程被创建时,ID值122,如果创建其他新进程对象,系统不会把相同的ID赋予给它,但是,如果第一个进程对象被释放,系统就可以把122赋予创建的下一个进程对象,因此,如果应用程序想要与它的“创建者”进行通信,最好不要使用ID,应该定义一个持久性更好的机制,对如内核对象和窗口句柄等。

 

如果想创建一个新进程,并等待结果,可用以下类似代码:

  1. PROCESS_INFORMATION pi;  
  2.     DWORD dwExitCode;  
  3.   
  4.     //Spawn the child process.  
  5.     BOOL fSuccess = CreateProcess(..., π);  
  6.   
  7.     if(fSuccess)  
  8.     {  
  9.         //Close the thread handle as soon as  
  10.         //it is no longer needed!  
  11.         CloseHandle(pi.hThread);  
  12.   
  13.         //Suspend our execution until  
  14.         //the child has terminated.  
  15.         WaitForSingleObject(pi.hProcess,INFINITE);  
  16.   
  17.         //The child process terminated;  
  18.         //get its exit code.  
  19.         GetExitCodeProcess(pi.hProcess,  
  20.             &dwExitCode);  
  21.   
  22.         //Close the process handle as soon as  
  23.         //it is no longer needed.  
  24.         CloseHandle(pi.hProcess);  
  25.     }  

It should be noted that WaitForSingleObject can be notified only when the process object is terminated, so the call to WaitForSingleObject will suspend the thread of the parent process until the child process terminates. When WaitForSingleObject returns, you can get the child process through GetExitCodeProcess. the exit code of the process

Note:
  The CreateProcess function is used to run a new program. The WinExec and LoadModule functions are still available, but they are also implemented by calling the CreateProcess function.

  In addition, the CreateProcess function creates a thread object in addition to creating a process. The thread will be created with an initialized stack, the size of which is determined by the description in the executable's header. Thread execution starts at the head of the file.

  Handles to new processes and new threads are created with global access. For either of these handles, if there is no security descriptor, then the handle can be used in any function that requires a handle type as a parameter. When a security descriptor is provided, when the handle is used in the next time, the access permission check is always performed first. If the access permission check denies access, the requesting process will not be able to use the handle to access the process.

  The process is assigned a 32-bit process identifier. This 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. Threads that are initialized in the process are also assigned a 32-bit thread identifier. This identifier is valid until the county is terminated and can be used to uniquely identify this thread in the system. These identifiers are returned in the PROCESS_INFORMATION structure.

  When specifying an application name in the lpApplicationName or lpCommandLine parameters, it does not matter whether the application name contains an extension or not, with one exception: an MS-DOS program or Windows program with a .com extension must contain .com extension.

  调用进程可以通过WaitForInputIdle函数来等待新进程完成它的初始化并等待用户输入。这对于父进程和子进程之间的同步是极其有用的,因为CreateProcess函数不会等待新进程完成它的初始化工作。举例来说,在试图与新进程关联的窗口之前,进程应该先调用WaitForInputIdle。

  首选的结束一个进程的方式是调用ExitProcess函数,因为这个函数通知这个进程的所有动态链接库(DLLs)程序已进入结束状态。其他的结束进程的方法不会通知关联的动态链接库。注意当一个进程调用ExitProcess时,这个进程的其他县城没有机会运行其他任何代码(包括关联动态链接库的终止代码)。

  ExitProcess, ExitThread, CreateThread, CreateRemoteThread,当一个进程启动时(调用了CreateProcess的结果)是在进程中序列化进行的。在一段地址空间中,同一时间内这些事件中只有一个可以发生。这意味着下面的限制将保留:
  *在进程启动和DLL初始化阶段,新的线程可以被创建,但是直到进程的DLL初始化完成前它们都不能开始运行。
  *在DLL初始化或卸下例程中进程中只能有一个线程。
  *直到所有的线程都完成DLL初始化或卸下后,ExitProcess函数才返回。

  在进程中的所有线程都终止且进程所有的句柄和它们的线程被通过调用CloseHandle函数终止前,进程会留在系统中。进程和主线程的句柄都必须通过调用CloseHandle函数关闭。如果不再需要这些句柄,最好在创建进程后立刻关闭它们。

当进程中最后一个线程终止时,下列的事件发生:
  *所有由进程打开的对象都会关闭。
  *进程的终止状态(由GetExitCodeProcess函数返回)从它的初始值STILL_ACTIVE变为最后一个结束的线程的结束状态。
  *主线程的线程对象被设置为标志状态,供其他等待这个对象的线程使用。
  *进程对象被设置为标志状态,供其他等待这个对象的线程使用。

假设当前在C盘上的目录是/MSVC/MFC且有一个环境变量叫做C:,它的值是C:/MSVC/MFC,就像前面lpEnvironment中提到过的那样,这样的系统驱动器上的目录信息在CreateProcess函数的lpEnvironment参数不为空时不会被自动传递到新进程里。一个应用程序必须手动地把当前目录信息传递到新的进程中。为了这样做,应用程序必须直接创建环境字符串,并把它们按字母顺序排列(因为Windows NT和Windows 95使用一种简略的环境变量),并把它们放进lpEnvironment中指定的环境块中。类似的,他们要找到环境块的开头,又要重复一次前面提到的环境块的排序。

一种获得驱动器X的当前目录变量的方法是调用GetFullPathName("x:",..)。这避免了一个应用程序必须去扫描环境块。如果返回的绝对路径是X:/,就不需要把这个值当作一个环境数据去传递了,因为根目录是驱动器X上的新进程的默认当前目录。


由CreateProcess函数返回的句柄对于进程对象具有PROCESS_ALL_ACCESS的访问权限。

由lpcurrentDirectory参数指定的当前目录室子进程对象的当前目录。lpCommandLine参数指定的第二个项目是父进程的当前目录。

For Windows NT, when a process is created with CREATE_NEW_PROCESS_GROUP specified, a call to SetConsoleCtrlHandler(NULL,True) is used on the new process, which means that CTRL+C has no effect on the new process . This allows upper-level surgical procedures to process CTRL+C messages themselves and optionally pass these signals to child processes. CTRL+BREAK is still valid and can be used to interrupt the execution of a process/process tree.

参见
AllocConsole, CloseHandle, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo, GetSystemDirectory, GetWindowsDirectory, LoadModule, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WaitForDebugEvent, WinExec

Shortcut information:
  import library: kernel32.lib
  header file: Winbase.h 

Original Portal: https://blog.csdn.net/hgy413/article/details/6200983

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324771964&siteId=291194637