MFC创建进程和进程的管理

文章目录

  • 为什么有这篇文章
  • STARTUPINFO
  • PROCESS_INFORMATION
  • ZeroMemory
    • memset
  • lpctstr
  • 最常见的 Windows 数据类型
  • TCHAR
    • 定义
    • 使用原理
  • MAX_PATH
    • MAX_PATH 这个变量是windows自己宏定义的变量
  • GetModuleFileName
  • 返回值
  • WaitForSingleObject 的用法
          • _T和_L
          • sprintf_s

为什么有这篇文章

操作系统实验的时候,第一个简单的程序就看的我傻眼,里面的很多语法从来没碰到过,这篇文章聚集了很多初学者可能不太懂得地方,算是我自己查资料的一个过程,也希望可以帮助到大家

#include 
//_tmain()是一个宏,支持unicode版本的main
int _tmain(int argc,_TCHAR *argv[])
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si,sizeof(si)); //分配内存
	si.cb = sizeof(si);
	ZeroMemory(&pi,sizeof(pi));
	if(!CreateProcess(_T("C:\\Windows\\System32\\mspaint.exe"),
		NULL,
		NULL,
		NULL,
		FALSE,
		0,
		NULL,
		NULL,
		&si,
		&pi))  //指定可执行模块的而字符串
	{
		fprintf(stderr,"Create Process Falied");
		return -1;
	}
	WaitForSingleObject(pi.hProcess,INFINITE);  //等待进程结束
	printf("child Compelete");
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}

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;           //请参见下一段和表4-7 的说明 
    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;

PROCESS_INFORMATION

  1. 调用Createprocess ()函数后,会自动地对该结构进行填充.
  2. 创建新进程可使系统建立一个进程内核对象和一个线程内核对象。在创建进程的时候,系统为每个对象赋予一个初始使用计数值1 。
  3. 关闭句柄只是告诉系统,你对进程或线程的统计数据不感兴趣。进程或线程将继续运行,直到它自己终止运行。
  4. 当进程内核对象创建后,系统赋予该对象一个独一无二的标识号,系统中的其他任何进程内核对象都不能使用这个相同的ID号。线程内核对象的情况也一样。
  5. 进程I D和线程I D共享相同的号码池。这意味着进程和线程不可能拥有相同的I D 。

ZeroMemory

ZeroMemory是美国微软公司的软件开发包SDK中的一个宏。 其作用是用0来填充一块内存区域。定义式如下

#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))  
#define ZeroMemory RtlZeroMemory 
  1. ZeroMemory实际是用memset实现的。
  2. ZeroMemory只能用于windows平台。

memset

void *memset(void *s,int ch,size_t n);
s字符串的前n个用ch字符串代替
是由C Run-time Library提供的提供的函数,作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

typedef struct _PROCESS_INFORMATION { 
    HANDLE hProcess; //存放每个对象的与进程相关的句柄 
    HANDLE hThread;        //返回的线程句柄。 
    DWORD dwProcessId;    //用来存放进程ID号 
    DWORD dwThreadId;      //用来存放线程ID号 
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

lpctstr

LPCTSTR用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。

LPCTSTR类型:

L表示long指针 这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。
P表示这是一个指针
C表示是一个常量
T表示在Win32环境中, 有一个_T宏
STR表示这个变量是一个字符串

bool CreateProcess 
( 
	LPCTSTR lpApplicationName, //指向一个NULL结尾的、用来指定可执行模块的字符串。 
	LPTSTR lpCommandLine,     //指向一个NULL结尾的、用来指定要运行的命令行。
	//如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行 
	//新运行的进程可以使用GetCommandLine函数获得整个命令行。 
	LPSECURITY_ATTRIBUTES lpProcessAttributes。 //指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL) ,那么句柄不能被继承。 
	LPSECURITY_ATTRIBUTES lpThreadAttributes, 
	BOOL bInheritHandles, //指示新进程是否从调用进程处继承了句柄。如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原 进程拥有完全相同的值和访问权限。 
	DWORD dwCreationFlags, //指定附加的、用来控制优先类和进程的创建的标志。 
	LPVOID lpEnvironment, //指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。 一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。 
	LPCTSTR lpCurrentDirectory, //指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数 为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。 
	LPSTARTUPINFO lpStartupInfo, //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。 
	LPPROCESS_INFORMATION lpProcessInformation //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
);
CreateProcess( 
appName,//应用程序名称 
pCmdLine, //命令行 
NULL, //进程句柄不能被继承 
NULL, //线程句柄不能被继承 
FALSE, 
NULL, 
NULL, 
NULL, 
&stStartUpInfo, 
&pProcessInfo); 
CloseHandle

最常见的 Windows 数据类型

MFC创建进程和进程的管理_第1张图片

typedef unsignedlong      DWORD;
typedef int                BOOL;
typedef unsignedchar      BYTE;
typedef unsignedshort     WORD;
typedef float              FLOAT;
typedef FLOAT              *PFLOAT;
typedef BOOLnear          *PBOOL;
typedef BOOLfar           *LPBOOL;
typedef BYTEnear          *PBYTE;
typedef BYTE far           *LPBYTE;
typedef intnear           *PINT;
typedef intfar            *LPINT;
typedef WORDnear          *PWORD;
typedef WORDfar           *LPWORD;
typedef longfar           *LPLONG;
typedef DWORDnear         *PDWORD;
typedef DWORDfar          *LPDWORD;
typedef voidfar           *LPVOID;
typedef CONST voidfar     *LPCVOID;
#include "iostream"
#include 
#include 
#include 
using namespace std;
static LPCTSTR g_szMutexName=_T("w2kdg.ProcTerm.mutex.Suicide");
//创建当前进程的克隆进程的简单方法
void StartClone()
{
	//提取当前可执行文件的文件名
	TCHAR szFilename[MAX_PATH];
	GetModuleFileName(NULL,szFilename,MAX_PATH);
	//格式化用于子进程的命令行,指明他是一个EXE文件和子进程
	TCHAR szCmdLine[MAX_PATH];
	//sprintf_s(szCmdLine,MAX_PATH,_T("\"%s\"child"),szFilename);
	sprintf(szCmdLine,_T("\"%s\"child"),szFilename);
	//子进程的启动信息结构
	STARTUPINFO si;
	::ZeroMemory((void*)(&si),sizeof(si));
	//应当是此结构的大小
	si.cb = sizeof(si);
	//返回的用于子进程的进程信息
	PROCESS_INFORMATION pi;
	//用同样的可执行文件名和命令行创建进程,并指明他是一个子进程
	BOOL bCreateOK = CreateProcess(
		szFilename,      //产生的应用程序名称(本EXE文件)
		szCmdLine,       //告诉人们这是一个子进程的标志
		NULL,            //用于进程的默认的安全性
		NULL,            //用于线程的默认的安全性
		FALSE,           //不继承句柄
		NULL,            //创建新窗口,使输出更直观
		NULL,            //新环境
		NULL,            //当前目录
		&si,             //启动信息结构
		&pi              //返回的进程的信息
		);
	//释放指向子进程的引用
	if(bCreateOK)
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
}
void Parent()
{
	//创建"自杀"互斥程序体
	HANDLE hMutexSuicide = ::CreateMutex(
		NULL,                //默认的安全性
		TRUE,                //最初拥有的
		g_szMutexName);      //为其命名
	if(hMutexSuicide != NULL)
	{
		//创建子进程
		cout << "Creating the child process." <<endl;
		StartClone();
		//暂停
		Sleep(5000);
		//令子进程"杀"掉自身
		cout << "Telling the child process to quit." << endl;
		ReleaseMutex(hMutexSuicide);
		//消除句柄
		CloseHandle(hMutexSuicide);
	}
}
void Chlid()
{
	//打开"自杀"互斥体
	HANDLE hMutexSuicide=OpenMutex(
		SYNCHRONIZE,              //打开用于同步
		FALSE,                    //不需要向下传递
		g_szMutexName);           //名称
	if(hMutexSuicide != NULL)
	{
		//报告正在等待指令
		cout << "Child waiting for suicide instructions." << endl;
		WaitForSingleObject(hMutexSuicide,INFINITE);
		//报告准备好终止,消除句柄
		cout << "Child quiting." << endl;
		CloseHandle(hMutexSuicide);
		Sleep(1000);
	}
}
int _tmain(int argc,_TCHAR* argv[])
{
	//决定其行为是父进程还是子进程
	if(argc>1 && strcmp(argv[1],"child")==0)
	{
		Chlid();
	}
	else
	{
		Parent();
	}
	return 0;
}

TCHAR

定义

TCHAR是通过define定义的字符串宏

使用原理

微软将这两套字符集及其操作进行了统一,通过条件编译(通过_UNICODE和UNICODE宏)控制实际使用的字符集,这样就有了_T("")这样的字符串,对应的就有了_tcslen这样的函数
为了存储这样的通用字符,就有了TCHAR:
当没有定义_UNICODE宏时,TCHAR = char,_tcslen =strlen
当定义了_UNICODE宏时,TCHAR = wchar_t , _tcslen = wcslen
当我们定义了UNICODE宏,就相当于告诉了编译器:我准备采用UNICODE版本。这个时候,TCHAR就会摇身一变,变成了wchar_t。而未定义UNICODE宏时,TCHAR摇身一变,变成了unsignedchar。这样就可以很好的切换宽窄字符集。
tchar可用于双字节字符串,使程序可以用于中日韩等国 语言文字处理、显示。使编程方法简化。

MAX_PATH

MAX_PATH 这个变量是windows自己宏定义的变量

MFC创建进程和进程的管理_第2张图片

GetModuleFileName

GetModuleFileName是计算机应用中的一个函数,用以获取当前进程已加载模块文件的完整路径。

DWORD GetModuleFileName(

    HMODULE hModule,
	//HMODULE hModule 装载一个程序实例的句柄。如果该参数为NULL,该函数返回该当前应用程序全路径。
	LPTSTR lpFilename,
	//LPTSTR lpFileName 是你存放返回的名字的内存块的指针,是一个输出参数

    DWORD nSize
	//DWORD nSize,装载到缓冲区lpFileName的最大值
);

返回值

如果返回为成功,将在lpFileName的缓冲区当中返回相应模块的路径,如果所设的nSize过小,那么返回仅按所设置缓冲区大小返回相应字符串内容。

如果函数失败,返回值将为0,利用GetLastError可获得异常代码。

WaitForSingleObject 的用法

DWORD WaitForSingleObject(
                     HANDLE hHandle, 
                     DWORD dwMilliseconds				
                  );
 //参数 hHandle 是一个事件的句柄
 //第二个参数 dwMilliseconds 是时间间隔
 //如果时间是有信号状态返回 WAIT_OBJECT_0 
 //如果时间超过 dwMilliseconds 值但时间事件还是无信号状态则返回 WAIT_TIMEOUT

WaitForSingleObject 函数用来检测 hHandle 事件的信号状态,当函数的执行时间超过 dwMilliseconds 就返回,但如果参数 dwMilliseconds 为 INFINITE 时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。

_T和_L

_T("")是一个宏,他的作用是让你的程序支持Unicode编码,因为Windows使用两种字符集ANSI和UNICODE,
前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。
而后者是双字节方式,方便处理双字节字符。
LPSTR:32bit指针指向一个字符串,每个字符占1字节
LPCSTR:32-bit指针指向一个常字符串,每个字符占1字节
LPCTSTR:32-bit指针指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义
LPTSTR:32-bit指针每字符可能占1字节或2字节,取决于Unicode是否定义
参考:https://blog.csdn.net/piaoliangjinjin/article/details/80800233

sprintf_s

在这里插入图片描述
MFC创建进程和进程的管理_第3张图片
sprintf_s是一个函数,其函数功能是将数据格式化输出到字符串。sprintf_s对于格式化string中的格式化的字符的有效性进行了检查,sprintf_s也携带着接收格式化字符串的缓冲区的大小。
sprintf_s将格式化字符串存到缓冲区,如果格式化字符串过大,则sprintf_s会返回一个空string和设置无效参数句柄为激活。

你可能感兴趣的:(操作系统)