Windows
进程间通信
发送消息
一般是自定义消息,使用SendMessage(需要有两个窗口)
同样的先创建一个进程A 用来发送消息 再创建一个进程B 接收消息
将二者放在同一个解决方案下
可以先创建A再添加B
A:发送消息
1 2 3 4 5 6 7
| #define MS_TEST WM_USER+1 void CADlg::OnBnClickedButton1() { HWND hWndB = ::FindWindow(NULL,"B"); ::SendMessage(hWndB,MS_TEST,0x12456789,0x98745612); }
|
B:接收消息
现在B这添加一个类导向
1 2 3 4 5 6 7
| afx_msg LRESULT CBDlg::OnMsTest(WPARAM wParam, LPARAM lParam) { CString strFmt; strFmt.Format("w:%08X,l:%08X", wParam, lParam); AfxMessageBox(strFmt); return 0; }
|
同时将自定义的消息扔到类视图的CBDlg中
然后运行 打开A 和B 的exe
这里点击发送消息 结果发现没有接收到消息 因为窗口没有标题 findwindows无法捕捉 于是没有获取到句柄
在类视图中添加显示窗口名 这样B就有了
然后点击发送消息 B即可响应了
WM_COPYDATA
可以携带少量数据,效率低(发生两次拷贝)
消息的传输:A进程的数据先拷到内核高2G的数据区 再从内核高2G的数据区拷到B进程(内核高2G的数据区是所有进程共用的)
参数1:目标窗口的句柄
参数3:本身窗口的句柄
参数2:
参数1:要传递给接收应用程序的数据类型
参数2: lpData 成员指向的数据的大小(以字节为单位)
参数3:要传递给接收应用程序的数据(可以是NULL)
在A中添加一个按钮为copydata
1 2 3 4 5 6 7 8 9 10 11 12
| void CADlg::OnBnClickedButton2() { HWND hWndB = ::FindWindow(NULL, "B"); COPYDATASTRUCT cps; cps.dwData = 0x12345678; cps.lpData = "你好, copydata"; cps.cbData = strlen((char *)cps.lpData); ::SendMessage(hWndB, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM) & cps); }
|
跟上次一样在B中添加类向导
1 2 3 4 5 6 7 8 9
| BOOL CBDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) {
CString strFmt; strFmt.Format("dw:%08X,lp:%s", pCopyDataStruct->dwData, pCopyDataStruct->lpData); AfxMessageBox(strFmt); return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); }
|
A可以将缓冲区中的数据发给B 数据的传输时单向的 B无法修改A中的数据
dll共享段
步骤:
1.定义共享段,并定义导出变量 导出变量需要初始化
1 2 3
| #pragma data_seg("CR40SharedSection") _declspec(dllexport)DWORD g_dwVal = 0; #pragma data_seg()
|
2.将此共享段声明为可共享
1
| #pragma comment(linker,"/SECTION:CR40SharedSection,RWS")
|
用dependency walker 查看导出结果
多个进程加载同一个dll 就可以通过dll共享段进行数据间的交互
在dll共享段中添加一个Use进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #pragma comment(lib,"../x64/debug/dll.lib") extern _declspec(dllimport) DWORD g_dwVal; void CUseDlg::OnBnClickedButton1() { SetDlgItemInt(EDT_READ,g_dwVal); }
void CUseDlg::OnBnClickedButton2() { g_dwVal = GetDlgItemInt(EDT_WRITE); }
|
由于不能直接运行dll所以得将Use设为运行项目
运行结果:
dll共享段中也可以为数组
dll:
1
| _declspec(dllexport)char g_sz[MAXBYTE] = {};
|
Use:
1 2 3 4 5 6 7 8 9 10 11 12 13
| extern _declspec(dllimport)char g_sz[MAXBYTE]; void CUseDlg::OnBnClickedButton1() { SetDlgItemText(EDT_READ, g_sz); }
void CUseDlg::OnBnClickedButton2() { GetDlgItemText(EDT_WRITE,g_sz,sizeof(g_sz)); }
|
文件映射
1.文件操作相关API
1 2 3 4 5 6
| 打开: CREATEFILE 关闭: CLOSEHANDLE 读: READFILE 写: WRITEFILE 文件指针: SETFILEPOINTER 文件大小: GETFILESIZE
|
参数1:路径
参数2:打开文件的访问权限(读还是写)
参数3:共享模式 A打开该文件 B同样可以对这个文件进行操作(删、读、写)若为0 则独占该文件 其他的无法打开
参数5:打开标志
参数6 :文件属性
参数4:成功读取的文件字节数
参数2指向低32位 参数3指向高32位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> #include<Windows.h> int main() { HANDLE hFile = CreateFile( "C:\\vs\\Dll共享段\\x64\\Debug\\Use.exe", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "打开文件失败" << std::endl; } BYTE aryBuff[MAXBYTE] = {}; DWORD dwByteReaded = 0; BOOL bRet = ReadFile(hFile, aryBuff, sizeof(aryBuff), &dwByteReaded, NULL);; if (!bRet) { CloseHandle(hFile); std::cout << "读取文件失败" << std::endl; return 0; } DWORD dwNewFilePos = SetFilePointer(hFile, 0x1000, NULL, FILE_BEGIN); if ( dwNewFilePos == INVALID_SET_FILE_POINTER) { CloseHandle(hFile); std::cout << "移动文件指针失败" << std::endl; return 0; }
char szBuff[] = { "hello file!" }; DWORD dwByteWrited = 0; bRet = WriteFile(hFile, szBuff, sizeof(szBuff), &dwByteWrited,NULL); if (!bRet) { CloseHandle(hFile); std::cout << "写入文件失败" << std::endl; return 0;
} CloseHandle(hFile); std::cout << "Hello World!\n"; }
|
2.文件映射用于读写文件数据
文件映射可以用于将磁盘上的文件映射到内存中。这样,文件的内容可以直接从内存中读取或写入,而不必通过磁盘I/O进行数据交换
步骤:
1.打开文件 createfile
2.创建文件映射对象 createfilemapping
参数6:用于进程间共享 若无则填NULL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <iostream> #include<Windows.h> #include<memory> using namespace std; int main() {
shared_ptr<HANDLE> pFileHandle =make_shared<HANDLE>( CreateFile( "C:\\vs\\Dll共享段\\x64\\Debug\\Use.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL), [](HANDLE hFile) {CloseHandle(hFile); }); if (pFileHandle.get() == INVALID_HANDLE_VALUE) { std::cout << "打开文件失败" << std::endl; return 0; } shared_ptr<HANDLE> pFileMap = make_shared<HANDLE>( CreateFileMapping(pFileHandle.get(), NULL, PAGE_READWRITE, 0, 0, NULL), [](HANDLE hFileMap) {CloseHandle(hFileMap); } ); if (pFileMap.get() == NULL) { std::cout << "创建文件映射对象失败" << std::endl; return 0; } }
|
3.将文件映射到内存 mapviewoffile
参数3、4:从文件的哪个位置开始映射
参数5:映射文件多大到内存
4.使用
5.将文件从内存撤销映射
FileTest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| int main() {
HANDLE hFile = CreateFile( "C:\\vs\\Dll共享段\\x64\\Debug\\Use.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); shared_ptr<HANDLE> pFileHandle (& hFile,[](HANDLE hFile) {CloseHandle(hFile); }); if (pFileHandle.get() == INVALID_HANDLE_VALUE) { std::cout << "打开文件失败" << std::endl; return 0; } HANDLE hFileMap = CreateFileMapping( hFile,NULL, PAGE_READWRITE, 0,0, NULL ); shared_ptr<HANDLE> pFileMap(&hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); }); if (pFileMap.get() == NULL) { std::cout << "创建文件映射对象失败" << std::endl; return 0; } LPVOID pBuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0,0, 0x1000 ); if (pBuff == 0) { cout << "撤销文件映射对象失败" << endl; return 0; } UnmapViewOfFile(pBuff); return 0; }
|
之后即可直接修改内存中的数据
6.关闭文件文件映射对象 closehandle
7.关闭文件 closehandle
3.文件映射用于进程间通信(带文件)
使用步骤:
1.打开文件映射对象 createfilemapping/open file mapping
2.将文件映射到内存 mapviewoffile
3.使用
4.将文件从内存撤销映射
5.关闭文件文件映射对象 closehandle
6.关闭文件 closehandle
在sharefilemap进程中修改数据 filetest中的数据也会修改 二者共享
sharefilemap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| HANDLE hFileMap = OpenFileMapping( FILE_MAP_ALL_ACCESS,FALSE,"CR40SharedMappingFile" ); shared_ptr<HANDLE> pFileMap(&hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); }); if (pFileMap.get() == NULL) { std::cout << "创建文件映射对象失败" << std::endl; return 0; } LPVOID pBuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0x1000 ); if (pBuff == 0) { cout << "撤销文件映射对象失败" << endl; return 0; }
UnmapViewOfFile(pBuff);
return 0; std::cout << "Hello World!\n";
|
4.文件映射用于进程间通信(无文件)
创建步骤:
1.创建文件映射对象 createfilemapping
2.将文件映射到内存 mapviewoffile
3.使用
4.将文件从内存撤销映射
5.关闭文件文件映射对象 closehandle
6.关闭文件 closehandle
使用步骤:
1.打开文件映射对象 createfilemapping/open file mapping
2.将文件映射到内存 mapviewoffile
3.使用
4.将文件从内存撤销映射
5.关闭文件文件映射对象 closehandle
6.关闭文件 closehandle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| HANDLE hFileMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x1000, "CR40SharedMappingFile" ); if (hFileMap == 0) { std::cout << "创建文件映射对象失败" << std::endl; return 0; } LPVOID pBuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0x1000 ); if (pBuff == 0) { cout << "撤销文件映射对象失败" << endl; return 0; }
UnmapViewOfFile(pBuff);
|