前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Windows 编程(多进程)

Windows 编程(多进程)

作者头像
全栈程序员站长
发布2022-07-13 19:51:59
发布2022-07-13 19:51:59
1.1K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Windows 编程(多进程)

进程组成:

  1. 操作系统用来管理进行的内核对象 内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是 操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护 该对象的各种信息.
  2. 地址空间 它包含所有可执行模块或 DLL 模块的代码和数据.另外,它也包含动态 内存分配的空间,例如线程的栈和堆分配空间

进程从来不执行任何东西,它只是纯种的容器,若要使进行完成某项操作,它必 须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空 间的中的代码.也就是,真正完成代码执行的是线程,而进程只是纯种的容器, 或者说是线程的执行环境.

创建进程函数

CreateProcess

代码语言:javascript
代码运行次数:0
复制
CreateProcessW(
    _In_opt_ LPCWSTR lpApplicationName,// 该字符串可以指定要执行的模块的完整路径和文件名
_Inout_opt_ LPWSTR lpCommandLine,  //命令行

_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
//该 结构确定子进程是否可以继承返回到新进程对象的句柄。如果//lpProcessAttributes为NULL,则不能继承该句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
//该 结构确定子进程是否可以继承返回到新线程对象的句柄。如果//lpThreadAttributes为NULL,则不能继承该句柄
_In_ BOOL bInheritHandles,
//如果此参数为TRUE,则新进程将继承调用进程中的每个可继承句柄。如果参数为FALSE,则不会继承句柄。请注意,继承的句柄与原始句柄具有相同的值和//访问权限
    _In_ DWORD dwCreationFlags,// 控制优先级类别和流程创建的标志 CREATE_NEW_CONSOLE
_In_opt_ LPVOID lpEnvironment,// 指向新进程的环境块的指针。如果此参数为//NULL,则新进程将使用调用进程的环境
//
    _In_opt_ LPCWSTR lpCurrentDirectory,// 进程当前目录的完整路径
    _In_ LPSTARTUPINFOW lpStartupInfo, //设置扩展属性
    _Out_ LPPROCESS_INFORMATION lpProcessInformation // 该 结构接收有关新进程的标识//信息
    );

lpStartupInfo结构体

代码语言:javascript
代码运行次数:0
复制
typedef struct _STARTUPINFOW {
    DWORD   cb;
    LPWSTR  lpReserved;
    LPWSTR  lpDesktop;
    LPWSTR  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;
}

PROCESS_INFORMATION结构体

代码语言:javascript
代码运行次数:0
复制
typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
}
代码语言:javascript
代码运行次数:0
复制
#include <Windows.h>
#include <stdio.h>


int main() {
	
	/*_In_ LPSTARTUPINFOW lpStartupInfo,
		_Out_ LPPROCESS_INFORMATION lpProcessInformation*/
	STARTUPINFO lpStartupInfo;
	memset(&lpStartupInfo, 0, sizeof(lpStartupInfo));
	lpStartupInfo.cb = sizeof(lpStartupInfo);
	PROCESS_INFORMATION lpProcessInformation;
	memset(&lpProcessInformation, 0, sizeof(lpProcessInformation));
	TCHAR commandline[] = L"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
	int a = CreateProcess(NULL, commandline, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &lpStartupInfo, &lpProcessInformation);
	if (a) {
		printf_s("Create Success iRet = %d\n", a);
		WaitForSingleObject(lpProcessInformation.hProcess, 3000);
		CloseHandle(lpProcessInformation.hProcess);
		CloseHandle(lpProcessInformation.hThread);
		lpProcessInformation.dwProcessId = 0;
		lpProcessInformation.dwThreadId = 0;
		lpProcessInformation.hProcess = NULL;
		lpProcessInformation.hThread = NULL;
	}
}

进程间通讯方式

  1. 剪切板
  2. 邮槽
  3. 匿名管道
  4. 命名管道
  5. Copy_Data

剪切板通讯

发送

代码语言:javascript
代码运行次数:0
复制
void CMFCApplication2Dlg::OnBnClickedButton1()
{	 
	
	//打开剪切板 
	if (OpenClipboard()) {
		//清空剪切板 
		EmptyClipboard();
		char* szSendbuf;
		CStringW strSendW;
		//获取编辑框内容
		GetDlgItemText(IDC_EDIT1, strSendW);
		CStringA stringA = (CStringA)strSendW;
		//申请一块内存
		HANDLE Plic =  GlobalAlloc(GMEM_MOVEABLE, stringA.GetLength() + 1);
		//将剪切板句柄加锁
		szSendbuf = (char*)GlobalLock(Plic);
		//stringA 内容复制到szSendbuf中
		strcpy(szSendbuf, stringA);
		GlobalUnlock(Plic);
		//内容放到剪切板中
		SetClipboardData(CF_TEXT, Plic);
		//关闭剪切板
		CloseClipboard();
	}

接受

代码语言:javascript
代码运行次数:0
复制
void CMFCApplication2Dlg::OnBnClickedButton2()
{
	HANDLE pilc;
	char* pBuf;
	if (OpenClipboard()) {
		if (IsClipboardFormatAvailable(CF_TEXT))
		{
		
			pilc = GetClipboardData(CF_TEXT);
			pBuf = (char*)GlobalLock(pilc);
			USES_CONVERSION;
			LPCWSTR strBuf = A2W(pBuf);
			GlobalUnlock(pilc);
			//SetDlgItemText(IDC_EDIT2, strBuf);
			SetDlgItemText(IDC_EDIT2, strBuf);
		}
		CloseClipboard();
	}
}

油槽通讯

使用邮槽通信的进程分为服务端和客户端。 邮槽由服务端创建, 在创建时需要指定邮 槽名, 创建后服务端得到邮槽的句柄。 在邮槽创建后, 客户端可以通过邮槽名打开邮槽, 在获得句柄后可以向邮槽写入消息。 邮槽通信是单向的, 只有服务端才能从邮槽中读取消息, 客户端只能写入消息。 消息 是先入先出的。 客户端先写入的消息在服务端先被读取。 通过邮槽通信的数据可以是任意格式的, 但是一条消息不能大于 424 字节。 邮槽除了在本机内进行进程间通信外, 在主机间也可以通信。 但是在主机间进行邮槽通 信, 数据通过网络传播时使用的是数据报协议(UDP), 所以是一种不可靠的通信。 通过网 络进行邮槽通信时, 客户端必须知道服务端的主机名或域名。

CreateMailslot

代码语言:javascript
代码运行次数:0
复制
HANDLE CreateMailslotA(
  LPCSTR                lpName,
  DWORD                 nMaxMessageSize,
  DWORD                 lReadTimeout,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
代码语言:javascript
代码运行次数:0
复制
void CMFCApplication2Dlg::OnBnClickedButton1()
{

	
	LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot");
	HANDLE hslot=  CreateMailslot(szSlotName, 0, 1000, NULL);

	if (hslot == INVALID_HANDLE_VALUE) {
	
	
	TRACE("CreateMailslot failed with %d\n", GetLastError());
	return ;
	}
	char szBuf[] = { 0 };
	DWORD dwRead;
	TRACE("Begin ReadFile");
	if (!ReadFile(hslot, szBuf, 100, &dwRead, NULL)) {
		MessageBox(NULL, L"读取失败",0 );
		CloseHandle(hslot);
		return;
	}
	MessageBox(NULL, (CString)szBuf, 0);

}
代码语言:javascript
代码运行次数:0
复制
void CMFCApplication2Dlg::OnBnClickedButton2()
{
	LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot");
	HANDLE hMailSlot =CreateFile(szSlotName, FILE_GENERIC_WRITE,FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hMailSlot == INVALID_HANDLE_VALUE) {
		TRACE("CreateFile failed with %d\n", GetLastError());

		return;
	
	}

	char szbuf[] = "Bingo is handsome";
	DWORD dwWrite;

	if (!WriteFile(hMailSlot, szbuf, strlen(szbuf) + 1, &dwWrite, NULL)) {
		MessageBox(NULL, L"CreateFile failed ", 0);
		/*TRACE("CreateFile failed with %d\n", GetLastError());*/
		CloseHandle(hMailSlot);
		return;
	}
	MessageBox(NULL, (CString)szbuf, 0);
	CloseHandle(hMailSlot);


}

匿名管道

匿名管道是一个没有命名的单向管道, 本质上就是一个共享的内存区域。 通常用来 在父进程和子进程之间通信。 只能实现本地两个进程之间的通信。 不能实现网络通 信。

代码语言:javascript
代码运行次数:0
复制
CreatePipe(
_Out_ PHANDLE hReadPipe, //该变量接收管道的读取句柄
_Out_ PHANDLE hWritePipe,// 该变量接收管道的写句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,//NULL
_In_ DWORD nSize //管道缓冲区的大小 0 :默认缓冲区大小
);
代码语言:javascript
代码运行次数:0
复制
void CMFCApplication3Dlg::OnBnClickedButton2create()
{
	SECURITY_ATTRIBUTES sa;
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0))
	{
		MessageBox(_T("匿名管道创建失败"));
		return;
	} 
		STARTUPINFO strStartupInfo; //用来指定新进程窗口如何显示
	memset(&strStartupInfo, 0, sizeof(strStartupInfo));
	strStartupInfo.cb = sizeof(strStartupInfo);
	strStartupInfo.dwFlags = STARTF_USESTDHANDLES;
	strStartupInfo.hStdInput = hReadPipe;
	strStartupInfo.hStdOutput = hWritePipe;
	strStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	PROCESS_INFORMATION szProcessInformation;
	memset
	(&szProcessInformation, 0, sizeof(szProcessInformation));
	int iRet = CreateProcess(
		_T("MailSlotClient.exe"),//子进程名
		NULL,
		NULL,
		NULL,
		TRUE,
		0,
		NULL,
		NULL,
		&strStartupInfo,
		&szProcessInformation
	);
	if (iRet)
	{
		//创建成功
		CloseHandle
		(szProcessInformation.hProcess);
		CloseHandle
		(szProcessInformation.hThread);
		szProcessInformation.dwProcessId = 0;
		szProcessInformation.dwThreadId = 0;
		szProcessInformation.hThread = NULL;
		szProcessInformation.hProcess = NULL;
	} else
	{
	CloseHandle
	(hReadPipe);
	CloseHandle
	(hWritePipe);
	hReadPipe = NULL;
	hWritePipe = NULL;
	MessageBox(_T("创建子进程失败"));
	return;
	}
}

读取与写入数据

代码语言:javascript
代码运行次数:0
复制
hReadCliPipe =GetStdHandle(STD_INPUT_HANDLE);
hWriteCliPipe = GetStdHandle(STD_OUTPUT_HANDLE);
//读取数据
{
char szBuf[100] = { 0 };
DWORD dwRead;

if (!ReadFile(hReadCliPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
} T
RACE("End PipeReadFile");
MessageBox((CStringW)szBuf);
}

//写入数据
{
char szBuf[] = "Bingo Bingo";
DWORD dwWrite;
if (!WriteFile(hWriteCliPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle
(hWriteCliPipe);
return;
} CloseHandle(hWriteCliPipe);
}

大多步骤与前面一致,但在strStartupInfo属性中需要进行设置strStartupInfo.hStdInputstrStartupInfo.hStdOutput的值为输入和输出的匿名管道句柄。

命名管道

支持网络之间不同进程的通信

CreateNamedPipe

代码语言:javascript
代码运行次数:0
复制
HANDLE CreateNamedPipeA(
LPCSTR lpName, // \.\pipe<i>pipename
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

客户端连接代码

代码语言:javascript
代码运行次数:0
复制
LPCTSTR szNamedPipeName = TEXT("\\\\.\\pipe\\mypipe");
if (0 == WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER))
{
MessageBox(_T("当前没有可以利用的管道"));
return;
} hNamedPipe =CreateFile(szNamedPipeName, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE
("CreateFile failed with %d\n", GetLastError());
MessageBox(_T("打开命名管道失败! "));
hNamedPipe = NULL;
return;
}
}
//读取文件

{
char szBuf[] = "Bingo Bingo";
DWORD dwWrite;
if (!WriteFile(hWriteCliPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle
(hWriteCliPipe);
return;
} CloseHandle
(hWriteCliPipe);
}


//写入文件
{
char szBuf[] = "Bingo Bingo";
DWORD dwWrite;
if (!WriteFile(hWriteCliPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle
(hWriteCliPipe);
return;
} C
loseHandle
(hWriteCliPipe);
}

服务端代码

代码语言:javascript
代码运行次数:0
复制
//1 创建一个命名管道
LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe");
hNamedPipe = CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE
("CreateNamedhPipe failed with %d\n", GetLastError());
MessageBox(_T("创建命名管道失败"));
return;
} // 2 等待客户端的连接
HANDLE hEvent = CreateEvent
(NULL, TRUE, FALSE, NULL);
if (NULL == hEvent)
{
MessageBox(_T("创建事件失败"));
CloseHandle
(hNamedPipe);
hNamedPipe = NULL;
return;
}
//1 创建一个命名管道
LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe");
hNamedPipe = CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE
("CreateNamedhPipe failed with %d\n", GetLastError());
MessageBox(_T("创建命名管道失败"));
return;
} // 2 等待客户端的连接
HANDLE hEvent = CreateEvent
(NULL, TRUE, FALSE, NULL);
if (NULL == hEvent)
{
MessageBox(_T("创建事件失败"));
CloseHandle(hNamedPipe);
hNamedPipe = NULL;
return;
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/119854.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年12月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Windows 编程(多进程)
    • 创建进程函数
    • 进程间通讯方式
      • 剪切板通讯
      • 油槽通讯
      • 匿名管道
      • 命名管道
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档