CProcessData : A template class to ease up SendMessage calls across processes





5.00/5 (39 votes)
Jun 10, 2005
1 min read

135840

1355
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.
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; //Populate 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; //Populate 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]
/* 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<typename T> class CProcessData { public: /* 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. */ 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); } } //WriteData is used to copy data to memory in the foreign process BOOL WriteData(const T& data) { return (m_hProcess && m_lpData) ? WriteProcessMemory( m_hProcess, m_lpData, (LPCVOID)&data, sizeof T, NULL) : FALSE; } //ReadData reads back data from memory in the foreign process BOOL ReadData(T* data) { return (m_hProcess && m_lpData) ? ReadProcessMemory( m_hProcess, m_lpData, (LPVOID)data, sizeof T, NULL) : FALSE; } //Templated ReadData that's used to read a specific data type from //a memory address located in the foreign process template<typename TSUBTYPE> BOOL ReadData( TSUBTYPE* data, LPCVOID lpData) { return m_hProcess ? ReadProcessMemory(m_hProcess, lpData, (LPVOID)data, sizeof TSUBTYPE, NULL) : FALSE; } //Gets the address of the allocated memory in the foreign process 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
andCloseHandle
were in the wrong order) - June 10, 2005 : Article first published.
- June 9, 2005 : Class written.