进程间通信

发送消息

一般是自定义消息,使用SendMessage发送

image-20240708093902035

新建项目

image-20240708094207376

image-20240708094329859

1
2
3
4
5
6
#define MS_TEST WM_USER+1 //自定义消息
void CA1Dlg::OnBnClickedButton1()
{
HWND hWndB = ::FindWindow(NULL, "B1");
::SendMessage(hWndB, MS_TEST, 0x12456789, 0x98745612);
}

image-20240708095109771

添加自定义消息,确定后点击编辑代码

image-20240708095238547

1
2
3
4
5
6
7
afx_msg LRESULT CB1Dlg::OnMsTest(WPARAM wParam, LPARAM lParam)
{
CString strFmt;
strFmt.Format("w:%08x,l:%08x", wParam, lParam);
AfxMessageBox(strFmt);
return 0;
}

在头文件处要添加定义

image-20240708100003219

在B1初始化处要给窗口添加名字

image-20240708112406286

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
BOOL CB1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码
SetWindowText(_T("B1"));
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

在外面的文件夹中打开A1.exe和B1.exe,然后点击发送消息,A1就会向B1发送消息

image-20240708130555594

WM_COPYDATA

可以携带少量数据,效率低

先将数据拷贝高2G内存中,然后再从高2G拷贝到目标进程中,发生两次拷贝,所以效率低

image-20240708105634631

image-20240708105758891

A1Dlg.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
void CA1Dlg::OnBnClickedButton2()
{
HWND hWndB1 = ::FindWindow(NULL, "B1");
COPYDATASTRUCT cps;
cps.dwData = 0x12345678;
cps.lpData = "你好,copydata";
cps.cbData = strlen((char*)cps.lpData);
::SendMessage(
hWndB1,
WM_COPYDATA,
(WPARAM)GetSafeHwnd(),
(LPARAM)&cps);
}

在类视图中选中CB1Dlg,在类向导中找到WM_COPYDATA并双击,添加到现有处理程序中,然后双击函数名开始编辑

image-20240708125758412

B1Dlg.cpp

1
2
3
4
5
6
7
8
9
BOOL CB1Dlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
CString strFmt;
strFmt.Format("dw:%08x,lp:%s",
pCopyDataStruct->dwData,
pCopyDataStruct->lpData);
AfxMessageBox(strFmt);
return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}

重新生成解决方案后运行A1.exe和B1.exe,点击WM_COPYDATA,A1就会向B1发送消息

image-20240708131322211

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")

image-20240708132302576

image-20240708132513607

找到SECTION并点入

image-20240708132543414

image-20240708132700463

R可读,W可写,S可共享

然后添加新建项目

image-20240708133839276

image-20240708133951104

image-20240708134140075

image-20240708134206288

点击两个按钮开始编辑

1
2
3
4
5
6
7
8
9
10
11
12
#pragma comment(lib,"../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);
}

运行后按读会读取一个0

image-20240708135546201

在写的地方填写数据后点击写,再点击读即可读取刚刚写入的数据

image-20240708135638730

还可以写入或读取字符串

dllmain.cpp

1
2
3
4
#pragma data_seg("CR40SharedSection")//开始
__declspec(dllexport) DWORD g_dwVal = 0;
__declspec(dllexport) char g_sz[MAXBYTE] = {};//要初始化
#pragma data_seg()//结束的位置

UseDlg.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma comment(lib,"../debug/dll.lib")
extern __declspec(dllimport) DWORD g_dwVal;
extern __declspec(dllimport) char g_sz[MAXBYTE];
void CUseDlg::OnBnClickedButton1()
{
//SetDlgItemInt(EDT_READ, g_dwVal);
SetDlgItemText(EDT_READ, g_sz);
}


void CUseDlg::OnBnClickedButton2()
{
//g_dwVal = GetDlgItemInt(EDT_WRITE);
GetDlgItemText(EDT_WRITE, g_sz, sizeof(g_sz));
}

运行后写入字符串即可读取

image-20240708140912706

文件映射

文件操作相关API

1
2
3
4
5
6
7
8
/*
打开 createFile
关闭 CloseFile
读 ReadFile
写 writeFile
文件指针 SetFilePointer/SetFilePoiterEx
文件大小 GetFileSize
*/

image-20240708143453398

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
45
46
47
48
49
50
51
// FileTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}
BYTE aryBuff[MAXBYTE] = {};
DWORD dwBytesReaded = 0;
BOOL bRet = ReadFile(hFile, aryBuff, sizeof(aryBuff), &dwBytesReaded, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "读取文件失败" << endl;
return 0;
}
//移动文件指针
DWORD dwNewFilePos = SetFilePointer(hFile, 0x1000, NULL , FILE_BEGIN);
if (dwNewFilePos == INVALID_SET_FILE_POINTER)
{
CloseHandle(hFile);
cout << "移动文件指针失败" << endl;
return 0;
}
char szBuff[] = { "hello file!!!" };
DWORD dwBytesWrited = 0;
bRet = WriteFile(hFile, szBuff, sizeof(szBuff), &dwBytesWrited, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "写入文件失败" << endl;
return 0;
}
CloseHandle(hFile);
cout << "Hello World!\n";
}

下断点进行调试,观察是否成功运行,最后有输出即说明成功运行

image-20240708150943213

文件映射用于读写文件数据

步骤

  1. 打开文件CreateFile
  2. 创建文件映射对象CreateFileMapping
  3. 将文件映射到内存MapViewOfFile
  4. 使用
  5. 将文件从内存撤销映射UnmapViewOfFile
  6. 关闭文件映射对象CloseHandle
  7. 关闭文件CloseHandle

将main函数中的内容全部选中提取函数

image-20240708151429916

image-20240708153524470

image-20240708153639812

image-20240708153706493

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// FileTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include "FileTest.h"
#include <memory>
using namespace std;

int TestFileApi()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}
BYTE aryBuff[MAXBYTE] = {};
DWORD dwBytesReaded = 0;
BOOL bRet = ReadFile(hFile, aryBuff, sizeof(aryBuff), &dwBytesReaded, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "读取文件失败" << endl;
return 0;
}
//移动文件指针
DWORD dwNewFilePos = SetFilePointer(hFile, 0x1000, NULL, FILE_BEGIN);
if (dwNewFilePos == INVALID_SET_FILE_POINTER)
{
CloseHandle(hFile);
cout << "移动文件指针失败" << endl;
return 0;
}
char szBuff[] = { "hello file!!!" };
DWORD dwBytesWrited = 0;
bRet = WriteFile(hFile, szBuff, sizeof(szBuff), &dwBytesWrited, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "写入文件失败" << endl;
return 0;
}
CloseHandle(hFile);
cout << "Hello World!\n";
return 0;
}

int main()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}

//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL,
PAGE_READWRITE,
0, 0,//整个文件
NULL);

if (hFileMap == NULL)
{
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

LPVOID pBuff = MapViewOfFile(hFileMap,
FILE_MAP_ALL_ACCESS,//可读可写
0, 0,//从文件头开始
0x1000);//映射0x1000到内存

if (pBuff == NULL)
{
CloseHandle(hFileMap);
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

//使用
//取消映射
UnmapViewOfFile(pBuff);
CloseHandle(hFileMap);
CloseHandle(hFile);

return 0;
}

下断点进行调试检查是否正常运行

文件映射用于进程间通信(带文件)

使用步骤

  1. 打开文件映射对象CreateFileMapping/OpenFileMapping
  2. 将文件映射到内存MapViewOfFile
  3. 使用
  4. 将文件从内存撤销映射UnmapViewOfFile
  5. 关闭文件映射对象CloseHandle
  6. 关闭文件CloseHandle

新建控制台应用

image-20240708164052110

image-20240708164548097

FileTest.cpp

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
45
46
47
48
49
50
51
int main()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}

//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL,
PAGE_READWRITE,
0, 0,//整个文件
"CR40SharedMappingFile");//将原来的NULL改成"CR40SharedMappingFile"

if (hFileMap == NULL)
{
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

LPVOID pBuff = MapViewOfFile(hFileMap,
FILE_MAP_ALL_ACCESS,//可读可写
0, 0,//从文件头开始
0x1000);//映射0x1000到内存

if (pBuff == NULL)
{
CloseHandle(hFileMap);
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

//使用
//取消映射
UnmapViewOfFile(pBuff);
CloseHandle(hFileMap);
CloseHandle(hFile);

return 0;
}

ShareFileMap.cpp

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
 // ShareFileMap.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <memory>
using namespace std;
int main()
{
//创建文件映射对象
HANDLE hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "CR40SharedMappingFile");
shared_ptr<HANDLE> pFileMap(&hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); });
if (pFileMap.get() == NULL)
{
cout << "创建文件映射对象失败" << endl;
return 0;
}
LPVOID pBuff = MapViewOfFile(hFileMap,
FILE_MAP_ALL_ACCESS,//可读可写
0, 0,//从文件头开始
0x1000);//映射0x1000到内存
if (pBuff == NULL)
{
cout << "创建文件映射对象失败" << endl;
return 0;
}
//使用
//取消映射
UnmapViewOfFile(pBuff);
std::cout << "Hello World!\n";
}

运行后下断点调试是否成功运行,若成功运行则两个进程之间可以数据共享

修改FileTest

image-20240708172944801

刷新后ShareFileMap的内存值也被修改

image-20240708173016051

运行结束可以正常输出

image-20240708173303707

文件映射用于进程间通信(无文件)

创建步骤:

  1. 创建文件映射对象CreateFileMapping
  2. 将文件映射到内存MapViewOfFile
  3. 使用
  4. 将文件从内存撤销映射UnmapViewOfFile
  5. 关闭文件映射对象CloseHandle
  6. 关闭文件CloseHandle

使用步骤:

  1. 打开文件映射对象CreateFileMapping/OpenFileMapping
  2. 将文件映射到内存MapViewOfFile
  3. 使用
  4. 将文件从内存撤销映射UnmapViewOfFile
  5. 关闭文件映射对象CloseHandle
  6. 关闭文件CloseHandle

image-20240708174324538

FileTest.cpp

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// FileTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include "FileTest.h"
#include <memory>
using namespace std;

int TestFileApi()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}
BYTE aryBuff[MAXBYTE] = {};
DWORD dwBytesReaded = 0;
BOOL bRet = ReadFile(hFile, aryBuff, sizeof(aryBuff), &dwBytesReaded, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "读取文件失败" << endl;
return 0;
}
//移动文件指针
DWORD dwNewFilePos = SetFilePointer(hFile, 0x1000, NULL, FILE_BEGIN);
if (dwNewFilePos == INVALID_SET_FILE_POINTER)
{
CloseHandle(hFile);
cout << "移动文件指针失败" << endl;
return 0;
}
char szBuff[] = { "hello file!!!" };
DWORD dwBytesWrited = 0;
bRet = WriteFile(hFile, szBuff, sizeof(szBuff), &dwBytesWrited, NULL);
if (!bRet)
{
CloseHandle(hFile);
cout << "写入文件失败" << endl;
return 0;
}
CloseHandle(hFile);
cout << "Hello World!\n";
return 0;
}

int ShareWithFile()
{
HANDLE hFile = CreateFile(
"C:\\Users\\lenovo\\source\\repos\\Dll共享段\\Debug\\Use.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,//共享读
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
cout << "打开文件失败" << endl;
return 0;
}

//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL,
PAGE_READWRITE,
0, 0,//整个文件
"CR40SharedMappingFile");

if (hFileMap == NULL)
{
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

LPVOID pBuff = MapViewOfFile(hFileMap,
FILE_MAP_ALL_ACCESS,//可读可写
0, 0,//从文件头开始
0x1000);//映射0x1000到内存

if (pBuff == NULL)
{
CloseHandle(hFileMap);
CloseHandle(hFile);
cout << "创建文件映射对象失败" << endl;
return 0;
}

//使用
//取消映射
UnmapViewOfFile(pBuff);
CloseHandle(hFileMap);
CloseHandle(hFile);
return {};
}

int main()
{
//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0, 0x1000,//整个文件
"CR40SharedMappingFile");

if (hFileMap == NULL)
{
cout << "创建文件映射对象失败" << endl;
return 0;
}

LPVOID pBuff = MapViewOfFile(hFileMap,
FILE_MAP_ALL_ACCESS,//可读可写
0, 0,//从文件头开始
0x1000);//映射0x1000到内存

if (pBuff == NULL)
{
CloseHandle(hFileMap);
cout << "创建文件映射对象失败" << endl;
return 0;
}

//使用
//取消映射
UnmapViewOfFile(pBuff);
CloseHandle(hFileMap);
return {};
return 0;
}

运行后下断点调试是否成功运行,若成功运行则两个进程之间可以数据共享

修改FileTest

image-20240708175056597

刷新后ShareFileMap的内存值也被修改

image-20240708175121815

运行结束可以正常输出

image-20240708175225513

管道

这集没讲完,详情请看下一集