zl程序教程

您现在的位置是:首页 >  系统

当前栏目

Windows创建进程

Windows进程 创建
2023-09-11 14:22:29 时间

1. WinExec()函数

这个函数还存在是为了兼容以前老式的16位机而存在的,它的函数原型为:
UINT WINAPI WinExec(
  _In_ LPCSTR lpCmdLine,
  _In_ UINT   uCmdShow
);
参数解析:

lpCmdLine:是命令行参数,也就是使用exe的文件路径和后面的命令行参数

uCmdShow:窗口显示的风格,参数的含义可以参考MSDN链接

返回值:


示例代码:

//************************************************************************
// 函数名称:    	CreateProcess_WinExec
// 访问权限:    	public 
// 创建日期:		2017/06/04
// 创 建 人:		
// 函数说明:		WinExc()函数,在16位机上使用 现在过时了
// 返 回 值:   	bool
//************************************************************************
bool CreateProcess_WinExec()
{
	using my_unit = unsigned int;
	my_unit return_value = WinExec("calc.exe", SW_SHOW);	//创建进程
	switch (return_value)
	{
	case 0:
		{
			cout << "The system is out of memory or resources." << endl;
			return false;
		}
	case ERROR_BAD_FORMAT:
		{
			cout << "The.exe file is invalid." << endl;
			return false;
		}
	case ERROR_FILE_NOT_FOUND:
		{
			cout << "The specified file was not found." << endl;
			return false;
		}
	case ERROR_PATH_NOT_FOUND:
		{
			cout << "The specified path was not found." << endl;
			return false;
		}
	default:
		break;
	}

	return true;
}

2. ShellExcute()函数

这个函数在指定的文件上操作,函数原型为:
HINSTANCE ShellExecute(
  _In_opt_ HWND    hwnd,
  _In_opt_ LPCTSTR lpOperation,
  _In_     LPCTSTR lpFile,
  _In_opt_ LPCTSTR lpParameters,
  _In_opt_ LPCTSTR lpDirectory,
  _In_     INT     nShowCmd
);
参数解析:
  _In_opt_ HWND    hwnd:父窗口的窗口句柄,当设置为NULL的时候表示不和任何窗口关联
  _In_opt_ LPCTSTR lpOperation:
edit
启动文档编辑器,然后打开lpFile指定的文件,若果lpFile指定的文件不是文档文件,创建进程将会失败。
explore
浏览由lpFile指定的文件夹
find
在指定的文件夹路径lpDirectory中搜索
open
打开由lpFile参数指向的目标,目标可以是文件或是文件夹
print
打印由lpFile指定的文件,如果指定的不是一个文档文件,函数调用将失败
  _In_     LPCTSTR lpFile:字符串指定要执行指定特定的文件或对象,要与lpOperation参数对应
  _In_opt_ LPCTSTR lpParameters:特定的可执行文件,后面可包含命令行参数
  _In_opt_ LPCTSTR lpDirectory:指向操作的路径,如果是NULL既是当前的运行路径
  _In_     INT     nShowCmd:窗口的显示风格

示例编码
//************************************************************************
// 函数名称:    	CreateProcess_ShellExecute
// 访问权限:    	public 
// 创建日期:		2017/06/04
// 创 建 人:		
// 函数说明:		ShellExecute()函数
// 返 回 值:   	bool
//************************************************************************
bool CreateProcess_ShellExecute()
{
	HINSTANCE  kk = ShellExecute(NULL, TEXT("open"), TEXT("test.txt"), NULL, NULL, SW_SHOW);
	return true;
}
test.txt是工程路径下存在的文件

3. ShellExcuteEx()函数

ShellExcuteEx()函数相对于ShellExcute()函数而言,采用了结构体传递参数,使得函数调用简洁了很多
函数原型:
BOOL ShellExecuteEx(
  _Inout_ SHELLEXECUTEINFO *pExecInfo
);
其中的参数是结构体SHELLEXECUTEINFO,结构体的定义如下
typedef struct _SHELLEXECUTEINFO {
  DWORD     cbSize;
  ULONG     fMask;
  HWND      hwnd;
  LPCTSTR   lpVerb;
  LPCTSTR   lpFile;
  LPCTSTR   lpParameters;
  LPCTSTR   lpDirectory;
  int       nShow;
  HINSTANCE hInstApp;
  LPVOID    lpIDList;
  LPCTSTR   lpClass;
  HKEY      hkeyClass;
  DWORD     dwHotKey;
  union {
    HANDLE hIcon;
    HANDLE hMonitor;
  } DUMMYUNIONNAME;
  HANDLE    hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
参数解释:
cbSize:
结构大小,以字节为单位。
fMask:
一个标志数组,用来设置其他成员的有效性。
hwnd:
可选。执行ShellExecuteEx的窗口句柄,可设为NULL。
lpVerb:
指定执行的动作,包括:edit ,explore ,find ,open,print, properties
lpFile:
以\0 结尾的字符串,指出 lpVerb 的操作对象的路径,被系统支持的操作包括文本的 open 、 print等
lpParameters:
可选。运行/打开程序的参数,如果打开的是一个文档,则该项无效
lpDirectory:
可选。指明工作目录的名字,成员没有说明,则默认为当前目录
nShow:
必须。指定打开的程序的显示方式,为SW_值中的一个。
hInstApp:
【out】如果设置SEE_MASK_NOCLOSEPROCESS S值并且ShellExecuteEx 调用成功,则该项的值大于32,如果调用失败,则将设置为 SE_ERR_XXX 的错误值。
lpIDList:
一个ITEMIDLIST结构的地址,用来存储成员的特别标识符,当fMask不包括SEE_MASK_IDLIST或SEE_MASK_INVOKEIDLIST时该项被忽略
lpClass:
用以指明文件类别的名字或GUID,当fMask不包括SEE_MASK_CLASSNAME时该项被忽略
hkeyClass:
获得已在系统注册的文件类型的Handle,当fMask不包括SEE_MASK_HOTKEY时该项被忽略
dwHotKey:
程序的热键关联,低位存储虚拟关键码(Key Code),高位存储修改标志位(HOTKEYF_),修改标志为(modifier flags)的详细列表请看WM_SETHOTKEY消息的描述,当fmask不包括SEE_MASK_HOTKEY时该项被忽略
DUMMYUNIONNAME 
hIcon :
取得对应文件类型的图标的Handle,当fMask不包括SEE_MASK_ICON时该项被忽略
hMonitor:
将文档显示在显示器上的Handle,当fMask不包括SEE_MASK_HMONITOR时该项被忽略
hProcess:
指向新启动的程序的句柄。若fMask不设为SEE_MASK_NOCLOSEPROCESS则该项值为NULL。但若程序没有启动,即使fMask设为SEE_MASK_NOCLOSEPROCESS,该值也仍为NULL。

实现示例
//************************************************************************
// 函数名称:    	CreateProcess_ShellExecuteEX
// 访问权限:    	public 
// 创建日期:		2017/06/04
// 创 建 人:		
// 函数说明:		ShellExecuteEX()函数
// 返 回 值:   	bool
//************************************************************************
bool CreateProcess_ShellExecuteEX()	
{
	SHELLEXECUTEINFO ShellInfo;
	memset(&ShellInfo, 0, sizeof(ShellInfo));
	ShellInfo.cbSize = sizeof(ShellInfo);
	ShellInfo.hwnd = NULL;
	ShellInfo.lpVerb = _T("open");
	ShellInfo.lpFile = _T("calc.exe"); // 此处写执行文件的绝对路径
	ShellInfo.nShow = SW_SHOWNORMAL;
	ShellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
	BOOL bResult = ShellExecuteEx(&ShellInfo);
	return true;
}
打开文件的例子
//************************************************************************
// 函数名称:    	CreateProcess_ShellExecuteEX
// 访问权限:    	public 
// 创建日期:		2017/06/04
// 创 建 人:		
// 函数说明:		ShellExecuteEX()函数
// 返 回 值:   	bool
//************************************************************************
bool CreateProcess_ShellExecuteEX()	
{
	SHELLEXECUTEINFO ShellInfo;
	memset(&ShellInfo, 0, sizeof(ShellInfo));
	ShellInfo.cbSize = sizeof(ShellInfo);
	ShellInfo.hwnd = NULL;
	ShellInfo.lpVerb = _T("open");
	ShellInfo.lpFile = _T("test.txt"); // 此处写执行文件的绝对路径
	ShellInfo.nShow = SW_SHOWNORMAL;
	ShellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
	BOOL bResult = ShellExecuteEx(&ShellInfo);
	return true;
}
打开网页的例子
SHELLEXECUTEINFO ShellInfo;              
memset(&ShellInfo, 0, sizeof(ShellInfo)); 
ShellInfo.cbSize = sizeof(ShellInfo);
ShellInfo.hwnd = NULL; 
ShellInfo.lpVerb = _T("open"); 
ShellInfo.lpFile = _T("http://www.sina.com");
ShellInfo.nShow = SW_SHOWNORMAL; 
ShellInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 
BOOL bResult = ShellExecuteEx(&ShellInfo);

4. CreateProcess()函数

CreateProcess()函数是当前主流的创建进程的函数,它的函数原型为
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
);
参数解释
lpApplicationName:
指向一个NULL结尾的、用来指定可执行模块的字符串。
这个字符串可以使可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。
这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数的最前面并由空格符与后面的字符分开。
这个被指定的模块可以是一个Win32应用程序。如果适当的子系统在当前计算机上可用的话,它也可以是其他类型的模块(如MS-DOS 或 OS/2)。
在Windows NT中,如果可执行模块是一个16位的应用程序,那么这个参数应该被设置为NULL,并且因该在lpCommandLine参数中指定可执行模块的名称。16位的应用程序是以DOS虚拟机或Win32上的Windows(WOW) 为进程的方式运行。
lpCommandLine:
指向一个NULL结尾的、用来指定要运行的命令行。
这个参数可以为空,那么函数将使用参数指定的字符串当作要运行的程序的命令行。
如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。
如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件:
1.当前应用程序的目录。
2.父进程的目录。
3.Windows目录。可以使用GetWindowsDirectory函数获得这个目录。
4.列在PATH环境变量中的目录。
     如果被创建的进程是一个以MS-DOS或16位Windows为基础的应用程序,lpCommandLine参数应该是一个以可执行文件的文件名作为第一个要素的绝对路径,因为这样做可以使32位Windows程序工作的很好,这样设置lpCommandLine参数是最强壮的。
lpProcessAttributes:
指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
lpThreadAttributes:
指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpThreadAttributes参数为空(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
含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。
值:CREATE_SHARED_WOW_VDM
含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果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标志一起使用。
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_ENVIRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。
请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块石油四个零字节结束的:两个代表字符串结束,另两个用来结束块。
lpCurrentDirectory:
指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。
lpStartupInfo:
指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
lpProcessInformation:
指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

返回值:
如果函数执行成功,返回非零值。
如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。


其中涉及到STARTUPINFOPROCESS_INFORMATION结构体
STARTUPINFO用于指定新进程的主窗口特性的一个结构。
typedef struct _STARTUPINFO   
{   
    DWORD cb;                //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO)   
    PSTR lpReserved;         //保留。必须初始化为NULL  
    PSTR lpDesktop;          //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联   
    PSTR lpTitle;            //用于设定控制台窗口的名称。如果lpTitle是NULL,则可执行文件的名字将用作窗口名.This parameter must be NULL for GUI or console processes that do not create a new console window.  
    DWORD dwX;               //用于设定应用程序窗口相对屏幕左上角位置的x 坐标(以像素为单位)。   
    DWORD dwY;               //对于GUI processes用CW_USEDEFAULT作为CreateWindow的x、y参数,创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员用于指明相对控制台窗口的左上角的位置  
    DWORD dwXSize;           //用于设定应用程序窗口的宽度(以像素为单位)  
    DWORD dwYSize;           //子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth、nHeight参数来创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度   
    DWORD dwXCountChars;     //用于设定子应用程序的控制台窗口的宽度(屏幕显示的字节列)和高度(字节行)(以字符为单位)   
    DWORD dwYCountChars;   
    DWORD dwFillAttribute;   //用于设定子应用程序的控制台窗口使用的文本和背景颜色   
    DWORD dwFlags;           //请参见下一段   
    WORD wShowWindow;        //用于设定如果子应用程序初次调用的ShowWindow 将SW_*作为nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符,除了SW_SHOWDEFAULT.   
    WORD cbReserved2;        //保留。必须被初始化为0   
    PBYTE lpReserved2;       //保留。必须被初始化为NULL  
    HANDLE hStdInput;        //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存   
    HANDLE hStdOutput;   
    HANDLE hStdError;   
} STARTUPINFO, *LPSTARTUPINFO;  
dwFlag参数说明:
STARTF_USESIZE                      //使用dwXSize 和dwYSize 成员   
STARTF_USESHOWWINDOW                //使用wShowWindow 成员   
STARTF_USEPOSITION                  //使用dwX 和dwY 成员   
STARTF_USECOUNTCHARS                //使用dwXCountChars 和dwYCount Chars 成员   
STARTF_USEFILLATTRIBUTE             //使用dwFillAttribute 成员   
STARTF_USESTDHANDLES                //使用hStdInput 、hStdOutput 和hStdError 成员   
STARTF_RUN_FULLSCREEN               //强制在x86 计算机上运行的控制台应用程序以全屏幕方式启动运行 
PROCESS_INFORMATION结构返回有关新进程及其主线程的信息RMATION
typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess; // 存放每个对象的与进程相关的句柄
  HANDLE hThread; // 返回的线程句柄
  DWORD dwProcessId; // 用来存放进程ID号
  DWORD dwThreadId; // 用来存放线程ID号
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFO
示例
//************************************************************************
// 函数名称:    	CreateProcess_CreateProcess
// 访问权限:    	public 
// 创建日期:		2017/06/04
// 创 建 人:		
// 函数说明:		CreateProcess()函数
// 返 回 值:   	bool
//************************************************************************
bool CreateProcess_CreateProcess()		
{
	PROCESS_INFORMATION pi;	//进程信息
	STARTUPINFO si;			//进程启动信息
	memset(&si, 0, sizeof(STARTUPINFO));
	si.cb = sizeof(si);
	si.wShowWindow = SW_SHOW;
	si.dwFlags = STARTF_USESHOWWINDOW;
	::CreateProcess(_T("C:\\Windows\\winsxs\\x86_microsoft-windows-calc_31bf3856ad364e35_6.1.7601.17514_none_abc56b2678fe1108\\calc.exe"),
		NULL, NULL, false, NULL, NULL, NULL, NULL, &si, &pi);
	return true;
}