我有一个Windows Mobile 6的Visual Studio 2008 C ++项目,有两个进程。我想要访问process1中包含的同一个函数。
该功能是Buzz
:
struct TEST_STRUCT
{
int bar;
WCHAR foo[ 20 ];
};
typedef int( *pfn_Buzz )( TEST_STRUCT* );
int Buzz( TEST_STRUCT* info );
Process1包含Buzz
的定义,并在内存映射文件中为它创建一个函数指针:
int Buzz( TEST_STRUCT* info )
{
info->bar = 1;
wsprintf( info->foo, L"Hello!" );
return 100;
}
int _tmain( int argc, _TCHAR* argv[] )
{
// create a memory-mapped file shared memory space that can be read by any process
HANDLE mapping = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof( pfn_Buzz ) , NULL );
LPVOID buzz_addr = ::MapViewOfFile( mapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof( pfn_Buzz ) );
// find our process' memory offset
DWORD offset = ::GetCurrentProcessIndex() + 0x02000000;
// copy the complete function address to the shared memory space
buzz_addr = ( LPVOID )( ( DWORD )&Buzz + offset );
// convert the function address to a string to send to process2.exe
WCHAR address[ 9 ] = { 0 };
wsprintf( address, L"%x", ( ( DWORD )buzz_addr ) );
// start process2.exe and wait for it to finish
PROCESS_INFORMATION pi = { 0 };
::CreateProcess( L"\\test_user.exe", address, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi );
::WaitForSingleObject( pi.hProcess, INFINITE );
::UnmapViewOfFile( buzz_addr );
::CloseHandle( mapping );
return 0;
}
Process2从Process1接收Buzz
的地址,将其强制转换为pfn_Buzz
函数指针,并执行它。
// process2.exe
int _tmain( int argc, _TCHAR* argv[] )
{
// get the address of the Buzz() function pointer
WCHAR* wszAddr = argv[ 1 ];
WCHAR* wszAddrEnd = &argv[ 1 ][ 8 ];
DWORD address = wcstol( wszAddr, &wszAddrEnd, 16 );
pfn_Buzz PFNBuzz = ( pfn_Buzz )address;
// execute buzz
TEST_STRUCT test = { 0 };
PFNBuzz( &test );
return 0;
}
不幸的是,当我尝试执行PFNBuzz
函数时,我在process2中收到了非法指令异常。
任何人都可以建议我可以改变以获得我追求的功能吗?
谢谢, PaulH
答案 0 :(得分:6)
您的问题源于流程A(启动流程B)具有2个完全不同的虚拟地址空间。您可以将一个函数指针传递给进程A,但是当它们的地址空间不同时,您传递的任何指针都会减少到另一个进程。这是流程的巨大奖金之一。
如果您希望在流程之间进行通信,则需要使用某种形式的Inter-Process Communication (IPC)。
有几种方法可以IPC under windows。在我看来,最通用的方法是使用套接字。套接字为您提供的优势是,您可以分离运行进程A和进程B的计算机,并仍然可以获得所需的功能。同样,没有什么能阻止在同一台机器上运行的两个进程。它提供的灵活性非常有用。
因此,假设您选择基于套接字的IPC方法,那么您实际所做的是Remote Procedure Call (RPC)。
正如您可能想象的那样,有许多不同的RPC方法。您可以使用DCOM或Corba。 Raknet是支持RPC的第三方库。还有许多其他解决方案。我强烈建议对此事进行大量研究。我为您提供的链接和关键字应该为您提供一个很好的起点:)
答案 1 :(得分:3)
您只需使用__declspec(dllexport)
导出该功能,然后使用GetProcAddress()
使用其名称加载它。如果在C ++中,只需记住extern "C"
声明以禁用名称修改。考虑:
extern "C" int __declspec(dllexport) Buzz( TEST_STRUCT* info ) { ... }
int main ( int, char ** )
{
pfn_Buzz buzz = GetProcAddress(GetModuleHandle(NULL), "Buzz");
// ...
}
然后,使用您选择的IPC方法传递函数名称。
答案 2 :(得分:2)
如果您希望两个进程都使用相同的函数,请将该函数放入DLL并将该DLL链接到这两个进程。每个进程都有自己的地址空间,因此一个进程中的地址可能在另一个进程中根本不起作用,即使它“有效”,它也会指向完全不同的地方。
虽然您正在将偏移量传递到父节点上的内存映射区域,但是当您尝试在该节点上访问它时,我看不到任何匹配的代码来映射相同的区域并将其基数添加到指针客户方。
Visual C ++有一个__based
指针类型,可以简化这一点。