跳转至

进程间通信API

概述

进程间通信(IPC)是不同进程之间交换数据的机制。Windows提供了多种IPC方式,包括管道、邮槽、共享内存、消息队列等。

管道

匿名管道

匿名管道用于父子进程间的单向通信。

CreatePipe - 创建匿名管道

C++
1
2
3
4
5
6
BOOL CreatePipe(
    PHANDLE               hReadPipe,   // 读取句柄
    PHANDLE               hWritePipe,  // 写入句柄
    LPSECURITY_ATTRIBUTES lpPipeAttributes, // 安全属性
    DWORD                 nSize        // 缓冲区大小
);

示例

C++
#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hReadPipe, hWritePipe;
    SECURITY_ATTRIBUTES sa = {0};
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    
    if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) {
        printf("CreatePipe failed: %d\n", GetLastError());
        return -1;
    }
    
    // 创建子进程
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};
    si.cb = sizeof(si);
    si.hStdOutput = hWritePipe;
    si.hStdError = hWritePipe;
    si.dwFlags = STARTF_USESTDHANDLES;
    
    CreateProcess(NULL, "cmd.exe /c dir", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    
    CloseHandle(hWritePipe);  // 关闭写入端
    
    // 读取输出
    char buffer[4096];
    DWORD bytesRead;
    while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL) && bytesRead > 0) {
        buffer[bytesRead] = '\0';
        printf("%s", buffer);
    }
    
    CloseHandle(hReadPipe);
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    
    return 0;
}

命名管道

命名管道可用于不相关进程间的双向通信。

CreateNamedPipe - 创建命名管道

C++
HANDLE CreateNamedPipe(
    LPCTSTR               lpName,       // 管道名称
    DWORD                 dwOpenMode,   // 打开模式
    DWORD                 dwPipeMode,   // 管道模式
    DWORD                 nMaxInstances, // 最大实例数
    DWORD                 nOutBufferSize, // 输出缓冲区大小
    DWORD                 nInBufferSize,  // 输入缓冲区大小
    DWORD                 nDefaultTimeOut, // 默认超时
    LPSECURITY_ATTRIBUTES lpSecurityAttributes // 安全属性
);

管道名称格式

Text Only
\\.\pipe\pipename

打开模式: - PIPE_ACCESS_DUPLEX:双向 - PIPE_ACCESS_INBOUND:入站 - PIPE_ACCESS_OUTBOUND:出站 - FILE_FLAG_OVERLAPPED:异步 - FILE_FLAG_WRITE_THROUGH:直写

管道模式: - PIPE_TYPE_BYTE:字节模式 - PIPE_TYPE_MESSAGE:消息模式 - PIPE_READMODE_BYTE:字节读取 - PIPE_READMODE_MESSAGE:消息读取 - PIPE_WAIT:阻塞 - PIPE_NOWAIT:非阻塞

ConnectNamedPipe - 等待客户端连接

C++
1
2
3
4
BOOL ConnectNamedPipe(
    HANDLE       hNamedPipe,
    LPOVERLAPPED lpOverlapped
);

DisconnectNamedPipe - 断开连接

C++
1
2
3
BOOL DisconnectNamedPipe(
    HANDLE hNamedPipe
);

服务端示例

C++
#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hPipe = CreateNamedPipe(
        L"\\\\.\\pipe\\MyPipe",
        PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        1,
        1024, 1024, 0, NULL
    );
    
    if (hPipe == INVALID_HANDLE_VALUE) {
        printf("CreateNamedPipe failed: %d\n", GetLastError());
        return -1;
    }
    
    printf("Waiting for client...\n");
    if (ConnectNamedPipe(hPipe, NULL)) {
        printf("Client connected\n");
        
        // 读取数据
        char buffer[1024];
        DWORD bytesRead;
        ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
        buffer[bytesRead] = '\0';
        printf("Received: %s\n", buffer);
        
        // 发送响应
        const char* response = "Hello from server!";
        DWORD bytesWritten;
        WriteFile(hPipe, response, strlen(response), &bytesWritten, NULL);
        
        DisconnectNamedPipe(hPipe);
    }
    
    CloseHandle(hPipe);
    return 0;
}

客户端示例

C++
#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hPipe = CreateFile(
        L"\\\\.\\pipe\\MyPipe",
        GENERIC_READ | GENERIC_WRITE,
        0, NULL, OPEN_EXISTING, 0, NULL
    );
    
    if (hPipe == INVALID_HANDLE_VALUE) {
        printf("CreateFile failed: %d\n", GetLastError());
        return -1;
    }
    
    // 发送数据
    const char* message = "Hello from client!";
    DWORD bytesWritten;
    WriteFile(hPipe, message, strlen(message), &bytesWritten, NULL);
    
    // 接收响应
    char buffer[1024];
    DWORD bytesRead;
    ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
    buffer[bytesRead] = '\0';
    printf("Response: %s\n", buffer);
    
    CloseHandle(hPipe);
    return 0;
}

邮槽

邮槽用于单向通信,适合广播消息。

CreateMailslot - 创建邮槽

C++
1
2
3
4
5
6
HANDLE CreateMailslot(
    LPCTSTR               lpName,
    DWORD                 nMaxMessageSize,
    DWORD                 lReadTimeout,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

邮槽名称格式

Text Only
\\.\mailslot\mailslotname

示例

C++
// 服务端
HANDLE hMailslot = CreateMailslot(L"\\\\.\\mailslot\\MySlot", 0, MAILSLOT_WAIT_FOREVER, NULL);
char buffer[1024];
DWORD bytesRead;
ReadFile(hMailslot, buffer, sizeof(buffer), &bytesRead, NULL);
CloseHandle(hMailslot);

// 客户端
HANDLE hMailslot = CreateFile(L"\\\\.\\mailslot\\MySlot", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
const char* message = "Hello!";
DWORD bytesWritten;
WriteFile(hMailslot, message, strlen(message), &bytesWritten, NULL);
CloseHandle(hMailslot);

共享内存

CreateFileMapping - 创建共享内存

C++
1
2
3
4
5
6
7
8
HANDLE CreateFileMapping(
    HANDLE                hFile,
    LPSECURITY_ATTRIBUTES lpAttributes,
    DWORD                 flProtect,
    DWORD                 dwMaximumSizeHigh,
    DWORD                 dwMaximumSizeLow,
    LPCTSTR               lpName
);

MapViewOfFile - 映射视图

C++
1
2
3
4
5
6
7
LPVOID MapViewOfFile(
    HANDLE hFileMappingObject,
    DWORD  dwDesiredAccess,
    DWORD  dwFileOffsetHigh,
    DWORD  dwFileOffsetLow,
    SIZE_T dwNumberOfBytesToMap
);

示例

C++
// 进程1:创建共享内存
HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, L"MySharedMemory");
LPVOID pData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
strcpy((char*)pData, "Hello from Process 1");
UnmapViewOfFile(pData);
CloseHandle(hMap);

// 进程2:访问共享内存
HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"MySharedMemory");
LPVOID pData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
printf("Read: %s\n", (char*)pData);
UnmapViewOfFile(pData);
CloseHandle(hMap);

内存映射文件

用于将文件映射到内存,实现文件的高效读写。

示例

C++
#include <windows.h>
#include <stdio.h>

int main() {
    // 创建文件
    HANDLE hFile = CreateFile(L"test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
    // 创建文件映射
    HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 4096, NULL);
    
    // 映射视图
    LPVOID pData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    
    // 写入数据
    strcpy((char*)pData, "Hello, Memory Mapped File!");
    
    // 同步到文件
    FlushViewOfFile(pData, 0);
    
    // 清理
    UnmapViewOfFile(pData);
    CloseHandle(hMap);
    CloseHandle(hFile);
    
    return 0;
}

消息队列

PostMessage - 投递消息

C++
1
2
3
4
5
6
BOOL PostMessage(
    HWND   hWnd,
    UINT   Msg,
    WPARAM wParam,
    LPARAM lParam
);

SendMessage - 发送消息

C++
1
2
3
4
5
6
LRESULT SendMessage(
    HWND   hWnd,
    UINT   Msg,
    WPARAM wParam,
    LPARAM lParam
);

自定义消息

C++
1
2
3
4
5
6
7
8
9
#define WM_MYMESSAGE (WM_USER + 100)

// 发送消息
PostMessage(hWnd, WM_MYMESSAGE, 0, 0);

// 接收消息(在窗口过程中)
case WM_MYMESSAGE:
    // 处理消息
    break;

WM_COPYDATA

用于窗口间传递数据。

示例

C++
// 发送端
COPYDATASTRUCT cds;
cds.dwData = 1;  // 自定义数据类型
cds.cbData = strlen(data) + 1;
cds.lpData = (PVOID)data;
SendMessage(hTargetWnd, WM_COPYDATA, (WPARAM)hMyWnd, (LPARAM)&cds);

// 接收端
case WM_COPYDATA:
    PCOPYDATASTRUCT pCds = (PCOPYDATASTRUCT)lParam;
    if (pCds->dwData == 1) {
        char* data = (char*)pCds->lpData;
        // 处理数据
    }
    return TRUE;

事件对象

用于进程间同步。

示例

C++
1
2
3
4
5
6
7
8
9
// 进程1
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, L"MyEvent");
WaitForSingleObject(hEvent, INFINITE);  // 等待信号
printf("Event signaled\n");

// 进程2
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, L"MyEvent");
SetEvent(hEvent);  // 发送信号
CloseHandle(hEvent);

互斥体

用于进程间互斥访问。

示例

C++
1
2
3
4
5
6
7
HANDLE hMutex = CreateMutex(NULL, FALSE, L"Global\\MyMutex");

WaitForSingleObject(hMutex, INFINITE);
// 临界区代码
ReleaseMutex(hMutex);

CloseHandle(hMutex);

信号量

控制资源访问数量。

示例

C++
1
2
3
4
5
6
7
HANDLE hSem = CreateSemaphore(NULL, 3, 3, L"MySemaphore");

WaitForSingleObject(hSem, INFINITE);  // 等待资源
// 使用资源
ReleaseSemaphore(hSem, 1, NULL);  // 释放资源

CloseHandle(hSem);

参考资料