在Windows编程中,跨进程通信是一个常见的需求。当需要与另一个进程中的控件交互时,例如发送消息或获取数据,通常需要使用到SendMessage
或PostMessage
函数。然而,这些函数要求手动管理内存分配和释放,以及进程句柄的关闭,这无疑增加了编程的复杂性。为了简化这一过程,可以使用CProcessData类,这是一个模板类,它封装了跨进程通信中的数据操作。
CProcessData类提供了一种便捷的方式来在不同进程之间传递数据。它通过封装OpenProcess
和VirtualAllocEx
等Windows API函数,使得在不同进程间读写数据变得更加简单。
CProcessData类的构造函数允许指定目标进程的ID、访问权限、内存分配类型和内存保护属性。如果进程ID设置为0,则默认使用当前进程的ID。
CProcessData(DWORD dwProcessId = 0, DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, DWORD flAllocationType = MEM_COMMIT, DWORD flProtect = PAGE_READWRITE);
WriteData方法用于将数据复制到目标进程的内存中。它接受一个引用参数,并将其内容写入到目标进程的内存地址。
BOOL WriteData(const T& data);
ReadData方法用于从目标进程的内存中读取数据。它接受一个指针参数,并将目标进程内存中的数据读取到该指针指向的变量中。
BOOL ReadData(T* data);
CProcessData类还提供了一个模板化的ReadData方法,允许从目标进程的特定内存地址读取特定类型的数据。
template BOOL ReadData(TSUBTYPE* data, LPCVOID lpData);
GetData方法用于获取在目标进程中分配的内存地址。
const T* GetData();
假设需要向另一个进程中的日期/时间选择控件发送DTM_SETSYSTEMTIME
消息。使用CProcessData类,可以简化这一过程。
SYSTEMTIME systim;
// 填充systim
CProcessData data(pid);
data.WriteData(systim);
DWORD dwResult = (DWORD)::SendMessage(hwnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)data.GetData());
if (dwResult == 0) {
DWORD err = GetLastError();
// ...
}
通过使用CProcessData类,不仅减少了代码量,还避免了忘记释放内存或关闭进程句柄的风险。
再比如,需要从另一个进程的Toolbar控件中获取按钮信息。使用CProcessData类,同样可以简化这一过程。
CProcessData data(pid);
::SendMessage(hwnd, TB_GETBUTTON, index, (LPARAM)data.GetData());
TBBUTTON tb;
data.ReadData(&tb);
CUSTOMDATA cus;
data.ReadData(&cus, (LPCVOID)tb.dwData);
CProcessData类使得跨进程通信变得更加简洁和安全。
CProcessData类是一个模板类,它提供了跨进程通信中数据操作的封装。以下是类的源代码参考:
/*
Author : Nishant Sivakumar
Date : June 9, 2005
Info : Template class that makes it easy to use data allocated
in a different process. Useful when making inter-process
SendMessage/PostMessage calls.
Contact : nish#voidnish.com
*/
//
ProcessData.h
#pragma once
template
class CProcessData
{
public:
CProcessData(DWORD dwProcessId = 0, DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, DWORD flAllocationType = MEM_COMMIT, DWORD flProtect = PAGE_READWRITE)
{
m_hProcess = OpenProcess(dwDesiredAccess, FALSE, dwProcessId ? dwProcessId : GetCurrentProcessId());
ASSERT(m_hProcess);
if (m_hProcess)
{
m_lpData = VirtualAllocEx(m_hProcess, NULL, sizeof(T), flAllocationType, flProtect);
ASSERT(m_lpData);
}
}
~CProcessData()
{
if (m_hProcess)
{
if (m_lpData)
{
VirtualFreeEx(m_hProcess, m_lpData, NULL, MEM_RELEASE);
}
CloseHandle(m_hProcess);
}
}
BOOL WriteData(const T& data)
{
return (m_hProcess && m_lpData) ? WriteProcessMemory(m_hProcess, m_lpData, (LPCVOID)&data, sizeof(T), NULL) : FALSE;
}
BOOL ReadData(T* data)
{
return (m_hProcess && m_lpData) ? ReadProcessMemory(m_hProcess, m_lpData, (LPVOID)data, sizeof(T), NULL) : FALSE;
}
template
BOOL ReadData(TSUBTYPE* data, LPCVOID lpData)
{
return m_hProcess ? ReadProcessMemory(m_hProcess, lpData, (LPVOID)data, sizeof(TSUBTYPE), NULL) : FALSE;
}
const T* GetData()
{
return (m_hProcess && m_lpData) ? (T*)m_lpData : NULL;
}
private:
T m_Data;
HANDLE m_hProcess;
LPVOID m_lpData;
};