Windows下创建进程-CreateProcess()

原文地址:https://blog.csdn.net/yuyan987/article/details/78644922 

函数说明:

CreateProcess是Windows下用于创建进程的API函数,用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。

函数原型:

BOOL CreateProcess

(
    LPCTSTR lpApplicationName,        
    LPTSTR lpCommandLine,        
    LPSECURITY_ATTRIBUTES lpProcessAttributes。
    LPSECURITY_ATTRIBUTES lpThreadAttributes,        
    BOOL bInheritHandles,        
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,        
    LPCTSTR lpCurrentDirectory,        
    LPSTARTUPINFO lpStartupInfo,        
    LPPROCESS_INFORMATION lpProcessInformation 

);

参数定义:

lpApplicationName
指向一个NULL结尾的、用来指定可执行模块的字符串。
这个字符串可以是可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。
这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数最前面并由空格符与后面的字符分开。
lpCommandLine
指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。
这个参数可以为空,那么函数将使用lpApplicationName参数指定的字符串当做要运行的程序的命令行。
如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。
lpProcessAttributes
指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
在Windows NT中:SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员指定了新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。
lpThreadAttributes
同lpProcessAttribute,不过这个参数决定的是线程是否被继承.通常置为NULL.
bInheritHandles
指示新进程是否从调用进程处继承了句柄。
如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。
dwCreationFlags
指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。
⑴值:CREATE_DEFAULT_ERROR_MODE
含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。
这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。
对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。
⑵值:CREATE_NEW_CONSOLE
含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。
⑶值:CREATE_NEW_PROCESS_GROUP
含义:新进程将是一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。
⑷值:CREATE_SEPARATE_WOW_VDM
如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。
⑸值:CREATE_SHARED_WOW_VDM
如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。
⑹值:CREATE_SUSPENDED
含义:新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。
⑺值:CREATE_UNICODE_ENVIRONMENT
含义:如果被设置,由lpEnvironment参数指定的环境块使用Unicode字符,如果为空,环境块使用ANSI字符。
⑻值:DEBUG_PROCESS
含义:如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。
⑼值:DEBUG_ONLY_THIS_PROCESS
含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。
⑽值:DETACHED_PROCESS
含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。
〔11〕值:CREATE_NO_WINDOW
含义:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。
dwCreationFlags参数
还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。如果下面的优先级类标志都没有被指定,那么默认的优先类是NORMAL_PRIORITY_CLASS,除非被创建的进程是IDLE_PRIORITY_CLASS。在这种情况下子进程的默认优先类是IDLE_PRIORITY_CLASS。
可以选择下面的标志中的一个:
优先级:HIGH_PRIORITY_CLASS
含义:指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序。一个例子是Windows任务列表,为了保证当用户调用时可以立刻响应,放弃了对系统负荷的考虑。确保在使用高优先级时应该足够谨慎,因为一个高优先级的CPU关联应用程序可以占用几乎全部的CPU可用时间。
优先级:IDLE_PRIORITY_CLASS
含义:指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断。例如屏幕保护程序。空闲优先级会被子进程继承。
优先级:NORMAL_PRIORITY_CLASS
含义:指示这个进程没有特殊的任务调度要求。
优先级:REALTIME_PRIORITY_CLASS
含义:指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致磁盘缓存不足或鼠标反映迟钝。
lpEnvironment
指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。
因为相等标志被当做分隔符,所以它不能被环境变量当做变量名。
与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。
环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENⅥRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。
请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块是由四个零字节结束的:两个代表字符串结束,另两个用来结束块。
lpCurrentDirectory
指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。
lpStartupInfo
指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
lpProcessInformation
指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
STARTUPINFO结构体:

    typedef struct _STARTUPINFO   
    {   
    DWORD cb;  
    LPTSTR lpReserved;    
    LPTSTR lpDesktop;   
    LPTSTR lpTitle;    
    DWORD dwX;    
    DWORD dwY;    
    DWORD dwXSize;  
    DWORD dwYSize;    
    DWORD dwXCountChars;    
    DWORD dwYCountChars;    
    DWORD dwFillAttribute;    
    DWORD dwFlags;    
    WORD wShowWindow;    
    WORD cbReserved2;    
    LPBYTE lpReserved2;    
    HANDLE hStdInput;    
    HANDLE hStdOutput;    
    HANDLE hStdError;  
    } STARTUPINFO, *LPSTARTUPINFO;

 

指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。

大多数应用程序都希望生成的应用程序只是使用默认值,最起码要全部初始化为0,再把cb成员设为此结构体的大小,如果没有清0,则新进程可能创建失败.

 

STARTUPINFO 结构的成员
成员     窗口,控制台还是两者兼有     作用
cb     两者兼有     包含S TA RT U P I N F O 结构中的字节数。如果M i c r o s o f t 将来扩展该结构,它可用作版本控制手段。应用程序必须将c b 初始化为s i z e o f ( S TA RT U P I N F O )
lpReserved     两者兼有     保留。必须初始化为N U L L
lpDesktop     两者兼有     用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果l p D e s k t o p 是N U L L (这是最常见的情况),那么该进程将与当前桌面相关联
lpTitle     控制台     用于设定控制台窗口的名称。如果l p Ti t l e 是N U L L ,则可执行文件的名字将用作窗口名
dwX
dwY     两者兼有     用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为单位)。只有当子进程用C W _ U S E D E FA U LT 作为C r e a t e Wi n d o w 的x 参数来创建它的第一个重叠窗口时,才使用这两个坐标。若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角
dwXSize     两者兼有     用于设定应用程序窗口的宽度和长度(以像素为单位)只有dwYsize 当子进程将C W _ U S E D E FA U LT 用作C r e a t e Wi n d o w 的n Wi d t h参数来创建它的第一个重叠窗口时,才使用这些值。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度
dwXCountChars
dwYCountChars     控制台     用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)
dwFillAttribute     控制台     用于设定子应用程序的控制台窗口使用的文本和背景颜色
dwFlags     两者兼有     请参见下一段和表4 - 7 的说明
wShowWindow     窗口     用于设定如果子应用程序初次调用的S h o w Wi n d o w 将S W _ S H O W D E FA U LT 作为n C m d S h o w 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于Show Wi n d o w 函数的任何一个S W _ *标识符
cbReserved2     两者兼有     保留。必须被初始化为0
lpReserved2     两者兼有     保留。必须被初始化为N U L L
hStdInput
hStdOutput
hStdError     控制台     用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,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用于标识控制台窗口的缓存

 

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

使用标志及含义
标志     含义
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秒内必须显示窗口,否则光标同样还原,
 

PROCESS_INFORMATION结构体:

typedef struct _PROCESS_INFORMATION {   
  HANDLE hProcess;   
  HANDLE hThread;   
  DWORD dwProcessId;   
  DWORD dwThreadId;   
} PROCESS_INFORMATION

运行实例:

注意:lpCommandLine是LPTSTR而不是LPCTSTR,所以这个参数不能是字符串常量,必须是可写的字符串数组。

如果要执行c:\\program files\\internet explorer\\iexplore.exe并传入命令行"http://community.csdn.net/"(用IE打开http://community.csdn.net网址),一般有两种方法。
方法一:

#include "stdafx.h"
#include 
#include 
 
void RunExe()
{
	STARTUPINFO stStartUpInfo;
	::memset(&stStartUpInfo, 0 ,sizeof(stStartUpInfo));
	stStartUpInfo.cb = sizeof(stStartUpInfo);
 
	PROCESS_INFORMATION stProcessInfo;
	::memset(&stProcessInfo, 0 ,sizeof(stProcessInfo));
 
	TCHAR szPath[] = _T("c:\\program files\\internet explorer\\iexplore.exe");
	TCHAR szCmd[] = _T(" http://community.csdn.net/");   //lpCommandLine的内容中开头需要一个空格,不然就和lpApplicationName连在一起去了
	try
	{
		bool bRet = ::CreateProcess(
			szPath,
			szCmd,
			NULL,
			NULL,
			false,
			CREATE_NEW_CONSOLE,
			NULL,
			NULL,
			&stStartUpInfo,
			&stProcessInfo);
 
		if (bRet)
		{
			//等待3s后关闭进程
			WaitForSingleObject(stProcessInfo.hProcess,3000L);
			::CloseHandle(stProcessInfo.hProcess);
			::CloseHandle(stProcessInfo.hThread);
			stProcessInfo.hProcess = NULL;
			stProcessInfo.hThread = NULL;
			stProcessInfo.dwProcessId = 0;
			stProcessInfo.dwThreadId = 0;
		}
		else
		{
			//如果创建进程失败,查看错误码
			DWORD dwErrCode = GetLastError();
			printf_s("ErrCode : %d\n",dwErrCode);
 
		}
	}
	catch( ... )
	{
	}
}
 
int main(int argc, char* argv[])   
{   
	RunExe();
 
	system("pause");
	return 0;   
}

方法二:

#include "stdafx.h"
#include 
#include 
 
void RunExe()
{
	STARTUPINFO stStartUpInfo;
	::memset(&stStartUpInfo, 0 ,sizeof(stStartUpInfo));
	stStartUpInfo.cb = sizeof(stStartUpInfo);
 
	PROCESS_INFORMATION stProcessInfo;
	::memset(&stProcessInfo, 0 ,sizeof(stProcessInfo));
 
	
	TCHAR szCmd[] = _T("\"c:\\program files\\internet explorer\\iexplore.exe\" http://community.csdn.net/");
 
	try
	{
		bool bRet = ::CreateProcess(
			NULL,
			szCmd,
			NULL,
			NULL,
			false,
			CREATE_NEW_CONSOLE,
			NULL,
			NULL,
			&stStartUpInfo,
			&stProcessInfo);
 
		if (bRet)
		{
			//等待3s后关闭进程
			WaitForSingleObject(stProcessInfo.hProcess,3000L);
			::CloseHandle(stProcessInfo.hProcess);
			::CloseHandle(stProcessInfo.hThread);
			stProcessInfo.hProcess = NULL;
			stProcessInfo.hThread = NULL;
			stProcessInfo.dwProcessId = 0;
			stProcessInfo.dwThreadId = 0;
		}
		else
		{
			//如果创建进程失败,查看错误码
			DWORD dwErrCode = GetLastError();
			printf_s("ErrCode : %d\n",dwErrCode);
 
		}
	}
	catch( ... )
	{
	}
}
 
int main(int argc, char* argv[])   
{   
	RunExe();
 
	system("pause");
	return 0;   
}   

 

你可能感兴趣的:(Windows)