Overview
CProcessData
is a template class that makes it easy to use data
allocated in a different process, and is useful when making inter-process
SendMessage
/PostMessage
calls.
Example Scenario - 1
Imagine that you are sending a DTM_SETSYSTEMTIME
message to a
Date/Time picker control in a different process.
Without CProcessData
SYSTEMTIME systim;
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID lpData = VirtualAllocEx(hProc, NULL,
sizeof SYSTEMTIME, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, lpData, (LPCVOID)&systim,
sizeof SYSTEMTIME, NULL);
DWORD dwResult = (DWORD)::SendMessage(hwnd,
DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&lpData);
if(dwResult == 0)
{
DWORD err = GetLastError();
}
VirtualFreeEx(hProc, lpData, NULL, MEM_RELEASE);
CloseHandle(hProc);
Using CProcessData
SYSTEMTIME systim;
CProcessData<SYSTEMTIME> data(pid);
data.WriteData(systim);
DWORD dwResult = (DWORD)::SendMessage(hwnd,
DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)data.GetData());
if(dwResult == 0)
{
DWORD err = GetLastError();
}
Note only have you saved on lines of code, but you don't run the risk of
forgetting to free the allocated memory or closing the process handle.
Example Scenario - 2
Imagine that you are retrieving toolbar info from a toolbar control in a
different process.
Without CProcessData
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID lpData = VirtualAllocEx(hProc, NULL,
sizeof TBBUTTON, MEM_COMMIT, PAGE_READWRITE);
::SendMessage(hwnd, TB_GETBUTTON, index, (LPARAM)lpData);
TBBUTTON tb;
ReadProcessMemory(hProc, lpData,(LPVOID)&tb,
sizeof TBBUTTON, NULL)
CUSTOMDATA cus;
ReadProcessMemory(hProc, (LPCVOID)tb.dwData, (LPVOID)&cus,
sizeof CUSTOMDATA, NULL)
VirtualFreeEx(hProc,lpData,NULL,MEM_RELEASE);
CloseHandle(hProc);
Using CProcessData
CProcessData<TBBUTTON> data(pid);
::SendMessage(hwnd, TB_GETBUTTON, index,
(LPARAM)data.GetData());
TBBUTTON tb;
data.ReadData(&tb);
CUSTOMDATA cus;
data.ReadData<CUSTOMDATA>(&cus,(LPCVOID)tb.dwData);
Pretty neat, huh?
Class Reference
Constructor
CProcessData(DWORD dwProcessId = 0, DWORD dwDesiredAccess =
PROCESS_ALL_ACCESS, DWORD flAllocationType = MEM_COMMIT, DWORD flProtect =
PAGE_READWRITE)
If you pass in a dwProcessId
of 0, the current process Id
is used. For the other arguments, see MSDN documentation for OpenProcess
and VirtualAllocEx
.
WriteData
BOOL WriteData(const T& data)
WriteData
copies data
to memory in the foreign
process
ReadData
BOOL ReadData(T* data)
ReadData
reads back from the memory in the foreign process into
data
.
ReadData (template version)
template<typename TSUBTYPE> BOOL ReadData(TSUBTYPE* data, LPCVOID
lpData)
Templated ReadData
that's used to read a specific data type from
a memory address located in the foreign process.
Full source listing
[Listing has been formatted to fit within 600 pixels. Actual source code
(included as a download) is formatted for wider screens]
#pragma once
template<typename T> 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<typename TSUBTYPE> 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;
};
History
- June 16, 2005 : Small bug fix in destructor. (
VirtualFreeEx
and CloseHandle
were in the wrong order)
- June 10, 2005 : Article first published.
- June 9, 2005 : Class written.