Windows 编程(多进程)

Windows编程(多进程)进程组成:操作系统用来管理进行的内核对象内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负

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

Windows 编程(多进程)

进程组成:

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

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

创建进程函数

CreateProcess

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结构体

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结构体

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
}
#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

剪切板通讯

发送

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();
	}

接受

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

HANDLE CreateMailslotA(
  LPCSTR                lpName,
  DWORD                 nMaxMessageSize,
  DWORD                 lReadTimeout,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
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);

}
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);


}

匿名管道

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

CreatePipe(
_Out_ PHANDLE hReadPipe, //该变量接收管道的读取句柄
_Out_ PHANDLE hWritePipe,// 该变量接收管道的写句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,//NULL
_In_ DWORD nSize //管道缓冲区的大小 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;
	}
}

读取与写入数据

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

HANDLE CreateNamedPipeA(
LPCSTR lpName, // \.\pipe<i>pipename
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

客户端连接代码

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);
}

服务端代码

//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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 死锁的产生条件和预防处理[通俗易懂]

    死锁的产生条件和预防处理

  • 【SPSS统计分析】SPSS聚类分析:一个案例演示聚类分析全过程(附SPSS 19.0中文版下载)「建议收藏」

    【SPSS统计分析】SPSS聚类分析:一个案例演示聚类分析全过程(附SPSS 19.0中文版下载)「建议收藏」摘要:案例数据源:有20种12盎司啤酒成分和价格的数据,变量包括啤酒名称、热量、钠含量、酒精含量、价格。数据来自《SPSSforWindows统计分析》。目录问题一:选择那些变量进行聚类?——采用“R型聚类”问题二:20中啤酒能分为几类?——采用“Q型聚类”问题三:用于聚类的变量对聚类过程、结果又贡献么,有用么?——采用“单因素方差分析”问题四:聚类结果的解释?——采用”均值比较描述统计“问题一:选择那些变量进行聚类?——采用“R型聚类”1、现在我们…

    2022年10月18日
  • phpstorm 激活码密钥无效(JetBrains全家桶)

    (phpstorm 激活码密钥无效)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

  • mysql自定义函数详解_mysqlinterval函数

    mysql自定义函数详解_mysqlinterval函数个人博客原文链接更多文章欢迎访问个人博客站点建定义函数的的基本语法如下–DELIMITER是用来设置边界符的DELIMITER//CREATEFUNCTION函数名(形参列表)RETURNS返回类型begin–函数体RETURNEND//DELIMITER;创建日期时间格式化函数DROPFUNCTIONIFEXISTS`FORMAT_DATE_TIME`;CREATE…

  • 安卓ExpandableListView的详细使用教程(附代码解析过程)「建议收藏」

    安卓ExpandableListView的详细使用教程(附代码解析过程)「建议收藏」ExpandableListView又称可扩展的ListView,它可以实现点击父项展开子项的效果,本文实现了一个比较精美的ExpandableListView。

  • 西门子plc冒泡法排序程序_博途graph编程讲解

    西门子plc冒泡法排序程序_博途graph编程讲解TIA博途中实现冒泡排序的两种SCL语言算法TIA博途软件版本:V15.0首先新建一个项目(具体过程这里就不演示了),添加一个FC块(或FB块均可),编程语言选择SCL,如下图,在FC的块接口中,定义我们需要的变量;一个数组型INT变量a用于存储需要排序的数据;一个INT型变量i:排序的起始序号;一个INT型变量j:排序的结束序号;一个TEMP型变量temp1:用于暂时存储中间比较的数据;利用SCL语言中的FOR循环语句,如下图中的程序,使得数组中的数据从a[i]开始比较到a[j],然后从小

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号