难,如何驱动读取进程内存其它进程的内存数据

怎么获取一个进程的内存数据_百度知道
怎么获取一个进程的内存数据
我有更好的答案
怎么说读取进程的所有内存数据呢,读到了也是一大堆你的变量都不一定能装下.用这个函数:readprocessmemory,指定内存的地址从而读取该地址处的内容,具体使用方法可以参考下MSDN或百度百科.
采纳率:94%
来自团队:
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。C/C++如何读取其他程序的内存?_百度知道
C/C++如何读取其他程序的内存?
我有更好的答案
越界操作,不过正在被使用的空间会有保护,这就需要HACK水平了
再详细点!
hook,挂钩子。
其他1条回答
为您推荐:
其他类似问题
您可能关注的内容
内存的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。[分享]如何读取其它进程地址空间的数据
如何读取其它进程地址空间的数据
问题的提出:
& && && & 当发现某一程序执行时,在内存中存在有用的信息后,需要把这些数据从内存中读出并将其翻
译成直观的图表形式表达。跟着,需要设计哪部分呢?需要将一个地址放入一个指针中,之后读取指针值
& && && & 可是这些读取的内存数据是不存在于我的程序中,众所周知,每一个进程有它的独立的地址空
间以致它不能“意外”访问属于其它程序的内存区域,所以为了读取这些数据需要找一种读取其它进程内
存空间的方法。
问题的解决思路:
& && && & 写一个可以接收一个进程并且提供读取这个进程内存地址的功能的程序。可以将其封装在一个
简单的小类库中使用它们。设计成类库主要是因为有时由于很多的情况下你也会用到它,如:你可以利用
这个类写一个调试工具。据我所知,所有调试工具都有读取调试程序的内存的功能。
问题解决的实现过程:
& && && & 该怎么读取其它进程的地址空间?答案在一个名叫ReadProcessMemory的API函数。
& && && & 使用方法:
& && && && && && & 1.用一个特定的读取模式打开进程,这由OpenProcess完成。
& && && && && && & 2.用ReadProcessMemory读取此进程内存中的指定地址。
& && && && && && & 3.之后,为避免资源泄露必须关闭进程句柄。这由CloseHandle帮助完成。
& && && & 具体过程:
& && && && && && & 1.在MSDN中找到这些API的声明:
& && && && && && && && & WINBASEAPI
& && && && && && && && & HANDLE
& && && && && && && && & WINAPI
& && && && && && && && & OpenProcess(
& && && && && && && && && &&&DWORD dwDesiredAccess,
& && && && && && && && && &&&BOOL bInheritHandle,
& && && && && && && && && &&&DWORD dwProcessId
& && && && && && && && && &&&);
& && && && && && && && &
& && && && && && && && & WINBASEAPI
& && && && && && && && & BOOL
& && && && && && && && & WINAPI
& && && && && && && && & ReadProcessMemory(
& && && && && && && && && &&&HANDLE hProcess,
& && && && && && && && && &&&LPCVOID lpBaseAddress,
& && && && && && && && && &&&LPVOID lpBuffer,
& && && && && && && && && &&&DWORD nSize,
& && && && && && && && && &&&LPDWORD lpNumberOfBytesRead
& && && && && && && && && &&&);
& && && && && && && && & WINBASEAPI
& && && && && && && && & BOOL
& && && && && && && && & WINAPI
& && && && && && && && & CloseHandle(
& && && && && && && && && &&&HANDLE hObject
& && && && && && && && && &&&);
& && && && && && &&&2.分析程序,找到此程序在内存中有用信息的地址(以扫雷程序为例)。
& && && && && && && && & 设:地雷区域为n行(高度)m列(宽度)
& && && && && && && && && &&&存放格式:1行1列;1行2列;...;1行m列;
& && && && && && && && && && && && && &2行1列;2行2列;...;2行m列;
& && && && && && && && && && && && && &.
& && && && && && && && && && && && && &.
& && && && && && && && && && && && && &.
& && && && && && && && && && && && && &n行1列;n行2列;...;n行m列;
& && && && && && && && && &&&产生地雷方式为:
& && && && && && && && && && && && && &1.随机宽度值=
& && && && && && && && && && && && && && & “在雷区宽度数值范围内(0-m)产生一随机数”+1
& && && && && && && && && && && && && &2.随机高度值=
& && && && && && && && && && && && && && & “在雷区高度数值范围内(0-n)产生一随机数”+1
& && && && && && && && && && && && && &3.由基址+32*随机高度值+随机高度值确定此地雷位置,并存
& && && && && && && && && && && && && &&&8F数值表示为地雷。
& && && && && && & 3.加载扫雷程序,在以其基址开始的地址中读取数据到分析程序中。
& && && && && && & 4.按内存存放格式将8F(雷)按图形方式标出显示。
& && && && && && & 5.在扫雷程序中标出地雷位置。
& && && && && && & 6.做个"扫雷英雄吧"!
& &&&学习如何将其它进程当中的数据读出,并以直观的图形方式表达程序分析结果。
读取过程实现程序
#include "stdafx.h"
LPCTSTR szClassName = TEXT( "WINCLASS" );
LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
& & & & PAINTSTRUCT& & & &
& & & & HDC& & & & & & & & hdc = NULL;
& & & & TCHAR& & & & strSysPath[ MAX_PATH ]& & & & = { '0' };
& & & & TCHAR& & & & buffer[ 512 ]& & & & & & & & = { '0' };
& & & & static PROCESS_INFORMATION ProcessI
& & & & static STARTUPINFO& & & && & StartupI
& & & & static HANDLE hMine = NULL;
& & & & OSVERSIONINFO versionI
& & & & int nWidthAddress& & & & = 0x0;
& & & & int nHeightAddress& & & & = 0x0;
& & & & int nMinesAddress& & & & = 0x0;
& & & & int nCellBaseAddress& & & & = 0x0;
& & & & static BYTE* byPtrIsMine = NULL;
& & & & static RECT* rectPtr = NULL;
& & & & static BYTE byWidth&&= 0;
& & & & static BYTE byHeight = 0;
& & & & static BYTE byMines&&= 0;
& & & & int index = 0;
& & & & switch ( uMsg )
& & & & case WM_CREATE:
& & & & & & & & GetVersionEx( & versionInfo );
& & & & & & & & if ( versionInfo.dwMajorVersion &= 5 )
& & & & & & & & {
& & & & & & & & & & & & // In WIN2K enviroment
& & & & & & & & & & & & if ( versionInfo.dwMinorVersion == 0 )
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & nWidthAddress& & & &&&= 0x10056F8;
& & & & & & & & & & & & & & & & nHeightAddress& & & &&&= 0x1005A68;
& & & & & & & & & & & & & & & & nMinesAddress& & & &&&= 0x1005A6C;
& & & & & & & & & & & & & & & & nCellBaseAddress = 0x1005700;
& & & & & & & & & & & & }
& & & & & & & & & & & & else
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & // In WINXP enviroment
& & & & & & & & & & & & & & & & nWidthAddress& & & &&&= 0x1005334;
& & & & & & & & & & & & & & & & nHeightAddress& & & &&&= 0x1005338;
& & & & & & & & & & & & & & & & nMinesAddress& & & &&&= 0x1005330;
& & & & & & & & & & & & & & & & nCellBaseAddress = 0x1005340;
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & else
& & & & & & & & {
& & & & & & & & & & & & MessageBox( \
& & & & & & & & & & & & & & & & NULL, \
& & & & & & & & & & & & & & & & TEXT( "THIS PROGRAMME NEED YOUR OPERATION SYSTEM IS WIN2K OR WINXP!" ), \
& & & & & & & & & & & & & & & & TEXT( "INFORMATION" ),
& & & & & & & & & & & & & & & & MB_OK | MB_ICONINFORMATION );
& & & & & & & & & & & & return 0;
& & & & & & & & }
& & & & & & & & // Execute the winmine game.
& & & & & & & & GetWindowsDirectory( strSysPath, MAX_PATH );
& & & & & & & & lstrcat( strSysPath, TEXT( "\\System32\\WinMine.exe" ) );
& & & & & & & & OutputDebugString( strSysPath );
& & & & & & & & OutputDebugString( "\n" );
& & & & & & & & ZeroMemory( & ProcessInfo, sizeof( PROCESS_INFORMATION ) );
& & & & & & & & ZeroMemory( & StartupInfo, sizeof( STARTUPINFO ) );
& & & & & & & & StartupInfo.cb = sizeof( StartupInfo );
& & & & & & & & if ( CreateProcess( \
& & & & & & & & & & & & & & & & strSysPath,
& & & & & & & & & & & & & & & & NULL, NULL, NULL, FALSE, 0, NULL, NULL, \
& & & & & & & & & & & & & & & & & StartupInfo, \
& & & & & & & & & & & & & & & & & ProcessInfo ) )
& & & & & & & & {
& & & & & & & & & & & & // Wait the CreateProcess function done
& & & & & & & & & & & & WaitForInputIdle( ProcessInfo.hProcess, INFINITE );
& & & & & & & & & & & & sprintf( buffer, "ThreadId: %d\n", ProcessInfo.dwThreadId );
& & & & & & & & & & & & OutputDebugString( buffer );
& & & & & & & & & & & & hMine = OpenProcess( PROCESS_VM_READ, TRUE, ProcessInfo.dwProcessId );
& & & & & & & & & & & & _ASSERT( hMine );
& & & & & & & & & & & & DWORD dwNumOfBytesRead = 0;
& & & & & & & & & & & & ReadProcessMemory( \
& & & & & & & & & & & & & & & & hMine, \
& & & & & & & & & & & & & & & & ( LPVOID ) nWidthAddress, \
& & & & & & & & & & & & & & & & & byWidth, \
& & & & & & & & & & & & & & & & 1, \
& & & & & & & & & & & & & & & & & dwNumOfBytesRead );
& & & & & & & & & & & & ReadProcessMemory( \
& & & & & & & & & & & & & & & & hMine, \
& & & & & & & & & & & & & & & & ( LPVOID ) nHeightAddress, \
& & & & & & & & & & & & & & & & & byHeight, \
& & & & & & & & & & & & & & & & 1, \
& & & & & & & & & & & & & & & & & dwNumOfBytesRead );
& & & & & & & & & & & & sprintf( buffer, "Mine Game's Width: %d\tMine Game's Height: %d\n", byWidth, byHeight );
& & & & & & & & & & & & OutputDebugString( buffer );
& & & & & & & & & & & & ReadProcessMemory( \
& & & & & & & & & & & & & & & & hMine, \
& & & & & & & & & & & & & & & & ( LPVOID ) nMinesAddress, \
& & & & & & & & & & & & & & & & & byMines, \
& & & & & & & & & & & & & & & & 1, \
& & & & & & & & & & & & & & & & & dwNumOfBytesRead );
& & & & & & & & & & & & sprintf( buffer, "Mine Game's Mines: %d\n", byMines );
& & & & & & & & & & & & OutputDebugString( buffer );
& & & & & & & & & & & & byPtrIsMine = new BYTE[ byWidth * byHeight ];
& & & & & & & & & & & & rectPtr = new RECT[ byWidth * byHeight ];
& & & & & & & & & & & & _ASSERT( byPtrIsMine );
& & & & & & & & & & & & _ASSERT( rectPtr );
& & & & & & & & & & & & if ( ! byPtrIsMine || ! rectPtr )
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & MessageBox( \
& & & & & & & & & & & & & & & & & & & & NULL, \
& & & & & & & & & & & & & & & & & & & & TEXT( "NO MORE MEMORY ALLOCATE !" ), \
& & & & & & & & & & & & & & & & & & & & TEXT( "INFORMATION" ), \
& & & & & & & & & & & & & & & & & & & & MB_OK | MB_ICONINFORMATION );
& & & & & & & & & & & & & & & & PostQuitMessage( 0 );
& & & & & & & & & & & & }
& & & & & & & & & & & & ZeroMemory( byPtrIsMine, byWidth * byHeight );
& & & & & & & & & & & & for ( int y = 0; y & byH y++ )
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & for ( int x = 0; x & byW x++ )
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & int nMineCellAddress = nCellBaseAddress + ( 32 * ( y + 1 ) ) + ( x + 1 );
& & & & & & & & & & & & & & & & & & & & ReadProcessMemory( \
& & & & & & & & & & & & & & & & & & & & & & & & hMine, \
& & & & & & & & & & & & & & & & & & & & & & & & ( LPVOID ) nMineCellAddress, \
& & & & & & & & & & & & & & & & & & & & & & & & & byPtrIsMine[ index ], \
& & & & & & & & & & & & & & & & & & & & & & & & 1, \
& & & & & & & & & & & & & & & & & & & & & & & & & dwNumOfBytesRead );
& & & & & & & & & & & & & & & & & & & & sprintf( buffer, "Value Is: 0x%x\n", byPtrIsMine[ index ] );
& & & & & & & & & & & & & & & & & & & & OutputDebugString( buffer );
& & & & & & & & & & & & & & & & & & & & rectPtr[ index ].left& & & & = ( x * 16 );
& & & & & & & & & & & & & & & & & & & & rectPtr[ index ].top& & & & = ( y * 16 );
& & & & & & & & & & & & & & & & & & & & rectPtr[ index ].right& & & & = ( x * 16 + 16 );
& & & & & & & & & & & & & & & & & & & & rectPtr[ index ].bottom& & & & = ( y * 16 + 16 );
& & & & & & & & & & & & & & & & & & & & index++;
& & & & & & & & & & & & & & & & }
& & & & & & & & & & & & }
& & & & & & & & & & & & index = 0;
& & & & & & & & }
& & & & & & & & else
& & & & & & & & {
& & & & & & & & & & & & MessageBox(
& & & & & & & & & & & & & & & & NULL, \
& & & & & & & & & & & & & & & & TEXT( "CANN'T CREATE WINMINE PROCESS !" ), \
& & & & & & & & & & & & & & & & TEXT( "INFORMATION" ), \
& & & & & & & & & & & & & & & & MB_OK | MB_ICONINFORMATION );
& & & & & & & & & & & & PostQuitMessage( 0 );
& & & & & & & & }
& & & & & & & & // Add the WS_EX_LAYERED attribute
& & & & & & & & SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong( hwnd, GWL_EXSTYLE ) ^ 0x80000 );
& & & & & & & & HINSTANCE hInst = LoadLibrary( "User32.dll ");
& & & & & & & & _ASSERT( hInst );
& & & & & & & & typedef BOOL ( WINAPI* SetWindowLayeredFunc )( HWND, COLORREF, BYTE, DWORD );
& & & & & & & & SetWindowLayeredFunc Func = NULL;
& & & & & & & & Func = ( SetWindowLayeredFunc ) GetProcAddress( hInst, "SetLayeredWindowAttributes" );
& & & & & & & & _ASSERT( Func );
& & & & & & & & Func( hwnd, 0, 128, 2 );
& & & & & & & & FreeLibrary( hInst );
& & & & & & & & RECT
& & & & & & & & GetWindowRect( hwnd, & rect );
& & & & & & & & SetWindowPos( \
& & & & & & & & & & & & hwnd, \
& & & & & & & & & & & & HWND_TOPMOST, \
& & & & & & & & & & & & rect.left, rect.top, \
& & & & & & & & & & & & 16 * byWidth + 9, 16 * byHeight + 28, \
& & & & & & & & & & & & SWP_NOMOVE );
& & & & & & & & return 0;
& & & & case WM_PAINT:
& & & & & & & & hdc = BeginPaint( hwnd, & ps );
& & & & & & & & _ASSERT( hdc );
& & & & & & & & for ( int i = 0; i & ( byWidth * byHeight ); i++ )
& & & & & & & & {
& & & & & & & & & & & & // This is a mine
& & & & & & & & & & & & if ( byPtrIsMine[ i ] == 0x8F )
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & HBRUSH hBrushRed = CreateSolidBrush( RGB( 255, 0, 0 ) );
& & & & & & & & & & & & & & & & _ASSERT( hBrushRed );
& & & & & & & & & & & & & & & & HGDIOBJ hOldBrush = SelectObject( hdc, hBrushRed );
& & & & & & & & & & & & & & & & _ASSERT( hOldBrush );
& & & & & & & & & & & & & & & & Rectangle( hdc, \
& & & & & & & & & & & & & & & & & & & & rectPtr[ i ].left, rectPtr[ i ].top, \
& & & & & & & & & & & & & & & & & & & & rectPtr[ i ].right, rectPtr[ i ].bottom );
& & & & & & & & & & & & & & & & SelectObject( hdc, hOldBrush );
& & & & & & & & & & & & }
& & & & & & & & & & & & else
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & Rectangle( hdc, \
& & & & & & & & & & & & & & & & & & & & rectPtr[ i ].left, rectPtr[ i ].top, \
& & & & & & & & & & & & & & & & & & & & rectPtr[ i ].right, rectPtr[ i ].bottom );
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & EndPaint( hwnd, & ps );
& & & & & & & & return 0;
& & & & case WM_DESTROY:
& & & & & & & & // Close the winmine game
& & & & & & & & PostQuitMessage( 0 );
& & & & & & & & if ( byPtrIsMine )
& & & & & & & & {
& & & & & & & & & & & & delete byPtrIsM
& & & & & & & & & & & & byPtrIsMine = NULL;
& & & & & & & & }
& & & & & & & & _ASSERT( byPtrIsMine == NULL );
& & & & & & & & if ( rectPtr )
& & & & & & & & {
& & & & & & & & & & & & delete rectP
& & & & & & & & & & & & rectPtr = NULL;
& & & & & & & & }
& & & & & & & & _ASSERT( rectPtr == NULL );
& & & & & & & & CloseHandle( hMine );
& & & & & & & & TerminateProcess( ProcessInfo.hProcess, 0 );
& & & & & & & & CloseHandle( ProcessInfo.hThread );
& & & & & & & & CloseHandle( ProcessInfo.hProcess );
& & & & & & & & return 0;
& & & & default:
& & & & & & & &
& & & & return DefWindowProc( hwnd, uMsg, wParam, lParam );
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow )
& & & & HWND& & & & hwnd = NULL;& & & & // Generic window handle
& & & & MSG& & & && & & & & & & & // Generic message
& & & & WNDCLASSEX
& & & & winclass.cbSize& & & & & & & & = sizeof( WNDCLASSEX );
& & & & winclass.style& & & & & & & & = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
& & & & winclass.lpfnWndProc& & & & = WndP
& & & & winclass.cbClsExtra& & & & = 0;
& & & & winclass.cbWndExtra& & & & = 0;
& & & & winclass.hInstance& & & & = hI
& & & & winclass.hIcon& & & & & & & & = LoadIcon( NULL, IDI_APPLICATION );
& & & & winclass.hCursor& & & & = LoadCursor(NULL, IDC_ARROW);
& & & & winclass.hbrBackground& & & & = ( HBRUSH ) GetStockObject( BLACK_BRUSH );
& & & & winclass.lpszMenuName& & & & = NULL;
& & & & winclass.lpszClassName& & & & = szClassN
& & & & winclass.hIconSm& & & & = LoadIcon( NULL, IDI_APPLICATION );
& & & & // Register the window class
& & & & if ( ! RegisterClassEx( & winclass ) )
& & & & & & & & return 0;
& & & & int cxScreen = GetSystemMetrics( SM_CXSCREEN );
& & & & int cyScreen = GetSystemMetrics( SM_CYSCREEN );
& & & & // Create the window
& & & & hwnd = CreateWindowEx(
& & & & & & & & & & & & NULL,& & & & & & & & & & & & & & & & & & & & // extended style
& & & & & & & & & & & & szClassName,& & & & & & & & & & & & & & & & // class
& & & & & & & & & & & & TEXT( "GAME" ),& & & & & & & & & & & & & & & & // title
& & & & & & & & & & & & WS_OVERLAPPEDWINDOW | WS_VISIBLE,& & & & // window style
& & & & & & & & & & & & cxScreen / 4, cyScreen / 4,& & & & & & & & // initial x,y
& & & & & & & & & & & & cxScreen / 2, cyScreen / 2,& & & & & & & & // initial width, height
& & & & & & & & & & & & NULL,& & & & & & & & & & & & & & & & & & & & // handle to parent
& & & & & & & & & & & & NULL,& & & & & & & & & & & & & & & & & & & & // handle to menu
& & & & & & & & & & & & hInstance,& & & & & & & & & & & & & & & & // instance of this application
& & & & & & & & & & & & NULL );& & & & & & & & & & & & & & & & & & & & // extra creation parms
& & & & _ASSERT( hwnd );
& & & & if ( ! hwnd )
& & & & & & & & return 0;
& & & & // enter main event loop
& & & & while ( TRUE )
& & & & & & & & if ( PeekMessage( & msg, NULL, 0, 0, PM_REMOVE ) )
& & & & & & & & {
& & & & & & & & & & & & if ( msg.message == WM_QUIT )
& & & & & & & & & & & & & & & &
& & & & & & & & & & & & // translate any accelerator keys
& & & & & & & & & & & & TranslateMessage( & msg );
& & & & & & & & & & & & // send the message to the window proc
& & & & & & & & & & & & DispatchMessage( & msg );
& & & & & & & & }
& & & & } // end while
& & & & UnregisterClass( szClassName, hInstance );
& & & & return ( msg.wParam );
支付方式:
最新回复 (2)
呵呵。。这个游戏修改器、外挂、辅助工具中用得比较多。
还没转够啊?
1.请先关注公众号。
2.点击菜单"更多"。
3.选择获取下载码。温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
有许多的人,想靠者时间忘记过去
而我的记忆,我想留都留不住
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
  在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。WIN32
API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换,就如同在WIN16中对本地进程进行读写操作一样。
 典型的WIN16两进程可以通过共享内存来进行数据交换:(1)进程A将GlobalAlloc(GMEM_SHARE...)API分配一定长度的内
存;(2)进程A将GlobalAlloc函数返回的句柄传递给进程B(通过一个登录消息);(3)进程B对这个句柄调用GlobalLock函数,并利
用GlobalLock函数返回的指针访问数据。这种方法在WIN32中可能失败,这是因为GlobalLock函数返回指向的是进程A的内存,由于进程
使用的是虚拟地址而非实际物理地址,因此这一指针仅与A进程有关,而于B进程无关。
  本文探讨了几种WIN32下进程之间通讯的几种实现方法,读者可以使用不同的方法以达到程序运行高效可靠的目的。
2、Windows95中进程的内存空间管理
  WIN32进程间通讯与Windows95的内存管理有密切关系,理解Windows95的内存管理对我们如下的程序设计将会有很大的帮助,下面我们讨论以下Windows95中进程的内存空间管理。
  在WIN16下,所有Windows应用程序共享单一地址,任何进程都能够对这一空间中属于共享单一的地址空间,任何进程都能够对这一空间中属于其他进程的内存进行读写操作,甚至可以存取操作系统本身的数据,这样就可能破坏其他程序的数据段代码。
 在WIN32下,每个进程都有自己的地址空间,一个WIN32进程不能存取另一个地址的私有数据,两个进程可以用具有相同值的指针寻址,但所读写的只是
它们各自的数据,这样就减少了进程之间的相互干扰。另一方面,每个WIN32进程拥有4GB的地址空间,但并不代表它真正拥有4GB的实际物理内存,而只
是操作系统利用CPU的内存分配功能提供的虚拟地址空间。在一般情况下,绝大多数虚拟地址并没有物理内存于它对应,在真正可以使用这些地址空间之前,还要
由操作系统提供实际的物理内存(这个过程叫"提交"commit)。在不同的情况下,系统提交的物理内存是不同的,可能是RAM,也可能是硬盘模拟的虚拟
3、WIN32中进程间的通讯
  在Windows 95中,为实现进程间平等的数据交换,用户可以有如下几种选择:
  * 使用内存映射文件
  * 通过共享内存DLL共享内存
  * 向另一进程发送WM_COPYDATA消息
调用ReadProcessMemory以及WriteProcessMemory函数,用户可以发送由GlobalLock(GMEM_SHARE,...)函数调用提取的句柄、GlobalLock函数返回的指针以及VirtualAlloc函数返回的指针。
3.1、利用内存映射文件实现WIN32进程间的通讯
  Windows95中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保留一段内存区域,把目标文件映射到这段虚拟内存中。在程序实现中必须考虑各进程之间的同步。具体实现步骤如下:
首先我们在发送数据的进程中需要通过调用内存映射API函数CreateFileMapping创建一个有名的共享内存:
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄,
//设为0xFFFFFFFF以创建一个进程间共享的对象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性
DWORD flProtect, // 保护方式
DWORD dwMaximumSizeHigh, //对象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 必须为映射文件命名
  与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多进程都对同一共享内存进行写访问,则必须
保持相互间同步。映射文件还可以指定PAGE_WRITECOPY标志,可以保证其原始数据不会遭到破坏,同时允许其他进程在必要时自由的操作数据的拷
  在创建文件映射对象后使用可以调用MapViewOfFile函数映射到本进程的地址空间内。
  下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件:
  HANDLE
hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF),
  NULL,PAGE_READWRITE,0,0x1000,"MySharedMem");
  并映射缓存区视图:
pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile,
  FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
  其他进程访问共享对象,需要获得对象名并调用OpenFileMapping函数。
  HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,
  FALSE,"MySharedMem");
  一旦其他进程获得映射对象的句柄,可以象创建进程那样调用MapViewOfFile函数来映射对象视图。用户可以使用该对象视图来进行数据读写操作,以达到数据通讯的目的。
  当用户进程结束使用共享内存后,调用UnmapViewOfFile函数以取消其地址空间内的视图:
if (!UnmapViewOfFile(pszMySharedMapView))
{ AfxMessageBox("could not unmap view of file"); }
3.2、利用共享内存DLL
  共享数据DLL允许进程以类似于Windows 3.1
DLL共享数据的方式访问读写数据,多个进程都可以对该共享数据DLL进行数据操作,达到共享数据的目的。在WIN32中为建立共享内存,必须执行以下步骤:
  首先创建一个有名的数据区。这在Visual C++中是使用data_seg pragma宏。使用data_seg
pragma宏必须注意数据的初始化:
#pragma data_seg("MYSEC")
char MySharedData[4096]={0};
#pragma data_seg()
然后在用户的DEF文件中为有名的数据区设定共享属性。
LIBRARY TEST
DATA READ WRITE
.MYSEC READ WRITE SHARED
  这样每个附属于DLL的进程都将接受到属于自己的数据拷贝,一个进程的数据变化并不会反映到其他进程的数据中。
  在DEF文件中适当地输出数据。以下的DEF文件项说明了如何以常数变量的形式输出MySharedData。
MySharedData CONSTANT
最后在应用程序(进程)按外部变量引用共享数据。
extern _export"C"{char * MySharedData[];}
进程中使用该变量应注意间接引用。
m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);
m_pStatic-&GetLine(0,*MySharedData,80);
3.3、用于传输只读数据的WM_COPYDATA
 传输只读数据可以使用Win32中的WM_COPYDATA消息。该消息的主要目的是允许在进程间传递只读数据。     Windows95在通过
WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送
方就不可能删除和修改数据:
SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
DWORD dwD//用户定义数据
DWORD cbD//数据大小
PVOID lpD//指向数据的指针
}COPYDATASTRUCT;
该结构用来定义用户数据。
3.4、直接调用ReadProcessMemory和WriteProcessMemory函数实现进程间通讯
通过调用ReadProcessMemory以及WriteProcessMemory函数用户可以按类似与Windows3.1的方法实现进程间通讯,在发送进程中分配一块内存存放数据,可以调用GlobalAlloc或者VirtualAlloc函数实现:
pApp-&m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024);
可以得到指针地址:
pApp-&mpszGlobalHandlePtr=(LPSTR)GlobalLock
(pApp-&m_hGlobalHandle);
在接收进程中要用到用户希望影响的进程的打开句柄。为了读写另一进程,应按如下方式调用OpenProcess函数:
HANDLE hTargetProcess=OpenProcess(
STANDARD_RIGHTS_REQUIRED|
PROCESS_VM_REDA|
PROCESS_VM_WRITE|
PROCESS_VM_OPERATION,//访问权限
FALSE,//继承关系
dwProcessID);//进程ID
为保证OpenProcess函数调用成功,用户所影响的进程必须由上述标志创建。
一旦用户获得一个进程的有效句柄,就可以调用ReadProcessMemory函数读取该进程的内存:
BOOL ReadProcessMemory(
HANDLE hProcess, // 进程指针
LPCVOID lpBaseAddress, // 数据块的首地址
LPVOID lpBuffer, // 读取数据所需缓冲区
DWORD cbRead, // 要读取的字节数
LPDWORD lpNumberOfBytesRead
使用同样的句柄也可以写入该进程的内存:
BOOL WriteProcessMemory(
HANDLE hProcess, // 进程指针
LPVOID lpBaseAddress, // 要写入的首地址
LPVOID lpBuffer, // 缓冲区地址
DWORD cbWrite, // 要写的字节数
LPDWORD lpNumberOfBytesWritten
如下所示是读写另一进程的共享内存中的数据:
ReadProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD),
_MAX_FIELD,&cb);
WriteProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,(LPSTR)STARS,
m_strGlobal.GetLength(),&cb);
4、进程之间的消息发送与接收
  在实际应用中进程之间需要发送和接收Windows消息来通知进程间相互通讯,发送方发送通讯的消息以通知接收方,接收方在收到发送方的消息后就可以对内存进行读写操作。
  我们在程序设计中采用Windows注册消息进行消息传递,首先在发送进程初始化过程中进行消息注册:
m_nMsgMapped=::RegisterWindowsMessage("Mapped");
m_nMsgHandle=::RegisterWindowsMessage("Handle");
m_nMsgShared=::RegisterWindowsMessage("Shared");
在程序运行中向接收进程发送消息:
CWnd* pWndRecv=FindWindow(lpClassName,"Receive");
pWndRecv-&SendMessage(m_MsgMapped,0,0);
pWndRecv-&SendMessage(m_nMsgHandle,
(UINT)GetCurrentProcessID(),(LONG)pApp-&m_hGlobalHandle);
pWndRecv-&SendMessage(m_nMsgShared,0,0);
可以按如下方式发送WM_COPYDATA消息:
static COPYDATASTRUCT//用户存放数据
pWnd-&SendMessage(WM_COPYDATA,NULL,(LONG)&cds);
接收方进程初始化也必须进行消息注册:
UNIT CRecvApp::
m_nMsgMapped=::RegisterWindowsMessage("Mapped");
CRecvApp::m_nMsgHandle=::RegisterWindowsMessage("Handle");
CRecvApp::m_nMsgShared=::RegisterWindowsMessage("Shared");
同时映射消息函数如下:
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnRegMsgMapped)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnRegMsgHandle)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnRegMsgShared)
在这些消息函数我们就可以采用上述技术实现接收进程中数据的读写操作了。
  从以上分析中我们可以看出Windows95的内存管理与Windows
3.x相比有很多的不同,对进程之间的通讯有较为严格的限制。这就确保了任何故障程序无法意外地写入用户的地址空间,而用户则可根据实际情况灵活地进行进
程间的数据通讯,从这一点上来讲Windows95增强应用程序的强壮性。
参考文献:
1、 David J.Kruglinski, Visual C++技术内幕, 北京:清华大学出版社,1995.
2、 Microsoft Co. Visual C++ 5.0 On Line Help.
下的进程间通讯及数据共享
15:03:42 阅读11 评论0 &&字号:大中小&
Windows 下有很多方法实现进程间通讯,比如用
socket,管道(Pipe),信箱(Mailslot),等等。但最基本最直接的还是使用内存共享。其他方法最终还是会绕道这里。
可想而知,如果物理内存只有一份,让这份内存在不同的进程中,映射到各自的虚拟地址空间上,每个进程都可以读取同一份数据,是一种最高效的数据交换方法。下面我们就讨论如何实现它。
共 享内存在 Windows 中是用 FileMapping 实现的。我们可以用 CreateFileMapping
创建一个内存文件映射对象, CreateFileMapping 这个 API
将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的文件,所以,就不需要调用 CreateFile 创建一个文件,
hFile 这个参数可以填写 INVALID_HANDLE_VALUE 。但是,文件长度是需要填的。Windows 支持长达
64bit 的文件,但是这里,我们的需求一定不会超过 4G , dwMaximumSizeHigh 一定是 0 ,长度填在
dwMaximumSizeLow 即可。然后调用 MapViewOfFile 映射到当前进程的虚拟地址上即可。一旦用完共享内存,再调用
UnmapViewOfFile 回收内存地址空间。
Windows 把 CreateFileMapping 和 MapViewOfFile 两个 API
分开做是有它的道理的。这是因为允许映射一个超过 4G 的文件,而地址空间最大只有 4G (实际上,一般用户的程序只能用到 2G) ,
MapViewOfFile 就可以指定文件的 Offset 而只映射一部分。
在 CreateFileMapping 的最后一个参数 pszName 填写一个名字,那么别的进程就可以用这个名字去调用
OpenFileMapping 来打开这个 FileMapping 对象,在新的进程内作映射。
不过,通过约定字符串的方法似乎不太优雅。
一个优雅的方法是,用 DuplicateHandle 在新进程中复制一份 FileMapping 对象出来,然后想办法把
Handle 通知新进程,比如用消息的方式传递过去。
如果需要共享内存的两个进程是父子关系,那么我们可以不用消息传递的方式来通知 FileMapping 的 Handle
。父进程可以用继承 Handle 的方式直接把 FileMapping 的 Handle 传递到子进程中。当然,在
CreateFileMapping 时就应该设置可以被继承的属性。
大约是这样:
SECURITY_ATTRIBUTES
sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;
handle=CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_READWRITE,0,size,NULL);
这样,在 CreateProcess 的时候,如果 bInheritHandles 参数为 TRUE
,所有有可被继承属性的内核对象都会被复制到子进程中。
注:内核对象的继承就是在 CreateProcess
创建子进程,但是子进程的主线程尚未活动之前,内核扫描当前进程中所有内核对象,检查出有可继承属性的那些,再用
DuplicateHandle
复制一份到子进程。由于是内核对象,在内核中实质只有一份,所有只是引用记数加一,父进程和子进程对同一内核对象的 Handle
一定是相同的。
复制内核对象的过程是由 CreateProcess 内部完成的,我们可以放心的把对象 Handle (和子进程相同)
通过命令行传递给子进程。或者,用环境变量传递也可以。
值得注意的是,子进程用完了这个 FileMapping 对象后一样需要 CloseHandle 减去引用计数。
CreateProcess 调用时,pszCommandLine 不能直接填上一个不可修改的字符串。例如:
CreateProcess("test.exe","test argument",...);
这样就是错误的,因为 "test argument" 会被编译器编译放到不可修改的数据段中。正确的方法是:
char cmdline[]="test argument";
CreateProcess("test.exe",cmdline,...);
这样,命令行的字符串就被放在堆栈上,是可以被读写的。
CreateProcess 的倒数第二个参数需要填写一个 STARTUPINFOW
结构,这个结构很复杂,通常填起来很麻烦。我们可以复制一份父进程的结构,再酌情修改。方法是:
STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION
GetStartupInfo(&si);
CreateProcess(...,&si,& pi);
这里, STARTUPINFO 结构的第一个长度信息通常应该填上,保证
GetStartupInfo(&si) 的正确执行。
Win32应用程序中进程间通信方法分析与比较
分类:进程间通信 &&
作者:李志刚 纪玉波 程小茁 崔朝辉
部分文章来自于网络,如有侵权请联系站长,以便及时卸下来
随着人们对应用程序的要求越来越高,单进程应用在许多场合已不能满足人们的要求。编写多进程/多线程程序成为现代程序设计的一个重要特点,在多进程程序设
计中,进程间通信是不可避免的。Microsoft Win32
API提供了多种进程间通信的方法,全面地阐述了这些方法的特点,并加以比较和分析,希望能给读者选择进程间通信方法提供参考。
1 进程与进程间通信
  进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。多进程/多线程是
Windows操作系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming
Interface, API)提供了大量支持应用程序间数据共享和交换的机制,这些机制行使的活动称为进程间通信(InterProcess
Communication, IPC),进程通信就是指不同进程间进行数据共享和数据交换。
  正因为使用Win32
API进行进程通信方式有多种,如何选择恰当的通信方式就成为应用开发中的一个重要问题,下面本文将对Win32中进程通信的几种方法加以分析和比较。
2 进程间通信方法
2.1 文件映射进程间通信
  文件映射(Memory-Mapped
Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。
API允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现了对文件中数据的共享。
  应用程序有三种方法来使多个进程共享一个文件映射对象。
  (1)继承:第一个进程建立文件映射对象,它的子进程继承该对象的句柄。
  (2)命名文件映射:第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外,第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。
  (3)句柄复制:第一个进程建立文件映射对象,然后通过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。第二个进程复制该句柄就取得对该文件映射对象的访问权限。
  文件映射是在多个进程间共享数据的非常有效方法,有较好的安全性。但文件映射只能用于本地机器的进程之间,不能用于网络中,而开发者还必须控制进程间的同步。
2.2 共享内存进程间通信
  Win32 API****享内存(Shared
Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替文件句柄(HANDLE),就表示了对应的文件映
射对象是从操作系统页面文件访问内存,其它进程打开该文件映射对象就可以访问该内存块。由于共享内存是用文件映射实现的,所以它也有较好的安全性,也只能
运行于同一计算机上的进程之间。
2.3 匿名管道进程间通信
  管道(Pipe)是一种具有两个端点的通信通道:有一端句柄的进程可以和有另一端句柄的进程通信。管道可以是单向-一端是只读的,另一端点是只写的;也可以是双向的一管道的两端点既可读也可写。
  匿名管道(Anonymous
Pipe)是在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。通常由父进程创建管道,然后由要通信的子进程继承通道的读
端点句柄或写端点句柄,然后实现通信。父进程还可以建立两个或更多个继承匿名管道读和写句柄的子进程。这些子进程可以使用管道直接通信,不需要通过父进
  匿名管道是单机上实现子进程标准I/O重定向的有效方法,它不能在网上使用,也不能用于两个不相关的进程之间。
2.4 命名管道
  命名管道(Named
Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是命名管道可以在不相关的进程之间和不同计算机之间使用,服务器
建立命名管道时给它指定一个名字,任何进程都可以通过该名字打开管道的另一端,根据给定的权限和服务器进程通信。
  命名管道提供了相对简单的编程接口,使通过网络传输数据并不比同一计算机上两进程之间通信更困难,不过如果要同时和多个进程通信它就力不从心了。
2.5 邮件槽
  邮件槽(Mailslots)提供进程间单向通信能力,任何进程都能建立邮件槽成为邮件槽服务器。其它进程,称为邮件槽客户,可以通过邮件槽的名字给
邮件槽服务器进程发送消息。进来的消息一直放在邮件槽中,直到服务器进程读取它为止。一个进程既可以是邮件槽服务器也可以是邮件槽客户,因此可建立多个邮
件槽实现进程间的双向通信。
  通过邮件槽可以给本地计算机上的邮件槽、其它计算机上的邮件槽或指定网络区域中所有计算机上有同样名字的邮件槽发送消息。广播通信的消息长度不能超过400字节,非广播消息的长度则受邮件槽服务器指定的最大消息长度的限制。
  邮件槽与命名管道相似,不过它传输数据是通过不可靠的数据报(如TCP/IP协议中的UDP包)完成的,一旦网络发生错误则无法保证消息正确地接收,
而命名管道传输数据则是建立在可靠连接基础上的。不过邮件槽有简化的编程接口和给指定网络区域内的所有计算机广播消息的能力,所以邮件槽不失为应用程序发
送和接收消息的另一种选择。
2.6 剪贴板进程间通信
  剪贴板(Clipped Board)实质是Win32
API中一组用来传输数据的函数和消息,为Windows应用程序之间进行数据共享提供了一个中介,Windows已建立的剪切(复制)-粘贴的机制为不
同应用程序之间共享不同格式数据提供了一条捷径。当用户在应用程序中执行剪切或复制操作时,应用程序把选取的数据用一种或多种格式放在剪贴板上。然后任何
其它应用程序都可以从剪贴板上拾取数据,从给定格式中选择适合自己的格式。
  剪贴板是一个非常松散的交换媒介,可以支持任何数据格式,每一格式由一无符号整数标识,对标准(预定义)剪贴板格式,该值是Win32
API定义的常量;对非标准格式可以使用Register Clipboard
Format函数注册为新的剪贴板格式。利用剪贴板进行交换的数据只需在数据格式上一致或都可以转化为某种格式就行。但剪贴板只能在基于Windows的
程序中使用,不能在网络上使用。
2.7 动态数据交换
  动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通信形式。应用程序可以使用DDE进行一次性数据传输,也可以当出现新数据时,通过发送更新值在应用程序间动态交换数据。
  DDE和剪贴板一样既支持标准数据格式(如文本、位图等),又可以支持自己定义的数据格式。但它们的数据传输机制却不同,一个明显区别是剪贴板操作几
乎总是用作对用户指定操作的一次性应答-如从菜单中选择Paste命令。尽管DDE也可以由用户启动,但它继续发挥作用一般不必用户进一步干预。DDE有
三种数据交换方式:
  (1) 冷链:数据交换是一次性数据传输,与剪贴板相同。
  (2) 温链:当数据交换时服务器通知客户,然后客户必须请求新的数据。
  (3) 热链:当数据交换时服务器自动给客户发送数据。
  DDE交换可以发生在单机或网络中不同计算机的应用程序之间。开发者还可以定义定制的DDE数据格式进行应用程序之间特别目的IPC,它们有更紧密耦合的通信要求。大多数基于Windows的应用程序都支持DDE。
2.8 对象连接与嵌入
  应用程序利用对象连接与嵌入(OLE)技术管理复合文档(由多种数据格式组成的文档),OLE提供使某应用程序更容易调用其它应用程序进行数据编辑的
服务。例如,OLE支持的字处理器可以嵌套电子表格,当用户要编辑电子表格时OLE库可自动启动电子表格编辑器。当用户退出电子表格编辑器时,该表格已在
原始字处理器文档中得到更新。在这里电子表格编辑器变成了字处理器的扩展,而如果使用DDE,用户要显式地启动电子表格编辑器。
  同DDE技术相同,大多数基于Windows的应用程序都支持OLE技术。
2.9 动态连接库
  Win32动态连接库(DLL)中的全局数据可以被调用DLL的所有进程共享,这就又给进程间通信开辟了一条新的途径,当然访问时要注意同步问题。
  虽然可以通过DLL进行进程间数据共享,但从数据安全的角度考虑,我们并不提倡这种方法,使用带有访问权限控制的共享内存的方法更好一些。&&&&&& 后记:如果担心DLL占据的内存随着进程的结束而被销毁,那就做成COM吧,呵呵!
2.10 远程过程调用实现进程间通信
API提供的远程过程调用(RPC)使应用程序可以使用远程调用函数,这使在网络上用RPC进行进程通信就像函数调用那样简单。RPC既可以在单机不同进程间使用也可以在网络中使用。
  由于Win32 API提供的RPC服从OSF-DCE(Open Software Foundation Distributed
Computing Environment)标准。所以通过Win32
API编写的RPC应用程序能与其它操作系统上支持DEC的RPC应用程序通信。使用RPC开发者可以建立高性能、紧密耦合的分布式应用程序。
2.11 NetBios函数
  Win32 API提供NetBios函数用于处理低级网络控制,这主要是为IBM
NetBios系统编写与Windows的接口。除非那些有特殊低级网络功能要求的应用程序,其它应用程序最好不要使用NetBios函数来进行进程间通信。
2.12 Sockets
  Windows Sockets规范是以U.C.Berkeley大学BSD
UNIX中流行的Socket接口为范例定义的一套Windows下的网络编程接口。除了Berkeley
Socket原有的库函数以外,还扩展了一组针对Windows的函数,使程序员可以充分利用Windows的消息机制进行编程。
  现在通过Sockets实现进程通信的网络应用越来越多,这主要的原因是Sockets的跨平台性要比其它IPC机制好得多,另外WinSock
2.0不仅支持TCP/IP协议,而且还支持其它协议(如IPX)。Sockets的唯一缺点是它支持的是底层通信操作,这使得在单机的进程间进行简单数
据传递不太方便,这时使用下面将介绍的WM_COPYDATA消息将更合适些。
2.13 WM_COPYDATA消息
  WM_COPYDATA是一种非常强大却鲜为人知的消息。当一个应用向另一个应用传送数据时,发送方只需使用调用SendMessage函数,参数是
目的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。接收方只需像处理其它消息那样处理WM_COPY
DATA消息,这样收发双方就实现了数据共享。
  WM_COPYDATA是一种非常简单的方法,它在底层实际上是通过文件映射来实现的。它的缺点是灵活性不高,并且它只能用于Windows平台的单机环境下。
API为应用程序实现进程间通信提供了如此多种选择方案,那么开发者如何进行选择呢?通常在决定使用哪种进程间通信方法之前应考虑以下一些问题:
  (1)应用程序是在网络环境下还是在单机环境下工作,如果是在网络环境下那么SOCKET进程间通信方式非常不错,如果单机本地进程间通信那么内存文件映射进程间通信是不错的选择。
(2)应用程序对性能的要求如何,如果对性能要求不高采用WM_COPYDATA方式完成进程间通信就非常简单.
阅读(6258)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'进程间共享数据',
blogAbstract:'原文:
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 读取进程内存 的文章

 

随机推荐