您的位置:首页 > 其它

进程外内存空间分配(续)

2004-04-21 10:56 337 查看
原理讲完了,下面给点代码吧。根据前面讲的步骤,也不算特别复杂,就是一组API的应用,不过写起来还是比较复杂的,为了方便使用,我总结出一组宏来方便代码编写。当时正热衷于ATL,对宏起到的作用非常崇拜,因此模仿了一下。我知道许多人不喜欢宏,但如果合理应用,还是非常管用的,如有异议,见ATL代码。
下面就是完整的宏代码:

//////////////////////////////////////////////////////////////////////////////

/// 简化进程外内存分配的宏.

/// 开始在hWnd所在的进程分配内存, size为分配内存的大小

#define DST_BEGIN_VM_ALLOC(hWnd, size) \

DST_BEGIN_OS_SPECIAL(VER_PLATFORM_WIN32_NT) \

DWORD dwProcessId; \

GetWindowThreadProcessId(hWnd, &dwProcessId); \

HANDLE hProcess = OpenProcess( \

PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, \

FALSE, dwProcessId); \

if (hProcess == NULL) \

{ \

::MessageBox(NULL, _T("Could not communicate with process"), \

_T("Error"), MB_OK | MB_ICONWARNING); \

} \

void* pRemoteBuffer = VirtualAllocEx(hProcess, \

NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

///////////////////////////////////////////////////////////

/// 结束进程外内存分配

#define DST_END_VM_ALLOC() \

VirtualFreeEx(hProcess, pRemoteBuffer, 0, MEM_RELEASE); \

CloseHandle(hProcess); \

DST_END_OS_SPECIAL()

//////////////////////////////////////////////////////////////////

/// 向已分配的进程地址中写入数据, offset为写入地址的偏移量

/// pBuffer 为要写入的数据缓冲区, size为写入内存的尺寸

#define DST_WRITE_VM(offset, pBuffer, size) \

::WriteProcessMemory(hProcess, (LPBYTE)pRemoteBuffer + offset, pBuffer, size, NULL);

///////////////////////////////////////////////////////////////

/// 从进程地址中读出数据, offset为读取地址的偏移量

/// pBuffer为读取结果缓冲区, size为读取字节数

#define DST_READ_VM(offset, pBuffer, size) \

::ReadProcessMemory(hProcess, (LPBYTE)pRemoteBuffer + offset, pBuffer, size, NULL);

///////////////////////////////////////////////////////////////////

/// 得到已分配的进程外内存地址, offset为偏移量

#define DST_GET_VM(offset) ((LPBYTE)pRemoteBuffer + offset)

/////////////////////////////////////////////////////////////////////

/// 开始执行特定操作系统代码

#define DST_BEGIN_OS_SPECIAL(osid) \

{ \

OSVERSIONINFO osinfo; \

memset(&osinfo, 0, sizeof(osinfo)); \

osinfo.dwOSVersionInfoSize = sizeof(osinfo); \

GetVersionEx(&osinfo); \

if (osinfo.dwPlatformId==osid) \

{

////////////////////////////////////////////////////////////////////////

/// 结束执行特定操作系统代码

#define DST_END_OS_SPECIAL() \

} \

}

有了这些宏,接下来的代码就很方便了。每条宏的作用不多讲了,反正代码都在这里,有兴趣的朋友自己看了。这里还是给出一些实际使用的代码吧,还是以得到ProgressBar的范围为例子。

PBRANGE range;
DST_BEGIN_VM_ALLOC(hWnd, 256);
DST_WRITE_VM(0, &range, sizeof(range));
::SendMessage(hWnd, PBM_GETRANGE, TRUE, (LPARAM)DST_GET_VM(0));
DST_READ_VM(0, &range, sizeof(range));
DST_END_VM_ALLOC()

好了,上面这段代码结束后,变量range就得到了目标进程中进度条的变化范围。稍微解释一下上面的代码吧:

hWnd是进度条窗口的句柄
DST_BEGIN_VM_ALLOC宏在进度条窗口所在进程分配了256字节的内存;
DST_WRITE_VM把本进程range变量的内容写到了目标进程刚分配的内存中;
SendMessage调用结束后,进度条窗口把进度条的范围写到了所在进程的内存中;
然后DST_READ_VM宏从目标进程的内存里读取数据,并填充到本进程的range变量中;
最后DST_END_VM_ALLOC宏做清理工作。
上面仅给出了最简单的示例,其实利用这些宏可以做很多非常有意思的工作,上面代码来自本人做的一个项目,叫做UI克隆器,它的作用是读取其他进程的界面,并生成一个完全一样的窗口,包括其所有控件、菜单等。当然,用来做普通的进程间内存共享也是不错的。
顺便说一下,某些API函数只有在Windows2000及更高版本的系统上才支持,因此,Windows98系统就不能使用这些功能了。为了让代码在98系统下编译运行不出现错误,所以定义了DST_BEGIN_OS_SPECIAL和DST_END_OS_SPECIAL宏,这两个宏已经在其他宏里面嵌套使用了,但也可以单独使用,不多说了,反正对于宏这个东西,我还是比较喜欢的,当然要合理使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: