Создание указателя функции кросс-процесса - PullRequest
4 голосов
/ 04 ноября 2010

У меня есть проект Visual Studio 2008 C ++ для Windows Mobile 6 с двумя процессами. Оба из которых я хотел бы иметь доступ к той же функции, которая содержится в 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 получает адрес для Buzz от Process1, преобразует его в указатель функции 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;
}

К сожалению, я получаю исключение Illegal Instruction в process2, когда пытаюсь выполнить функцию PFNBuzz.

Кто-нибудь может подсказать, что я мог бы изменить, чтобы получить функциональность, к которой я стремлюсь?

Спасибо, PaulH

Ответы [ 3 ]

6 голосов
/ 04 ноября 2010

Ваша проблема возникает из-за того, что Процесс A (который запускает Процесс B) имеет 2 совершенно разных виртуальных адресных пространства. Вы можете передать указатель на функцию в процесс A, но, поскольку их адресные пространства отличаются, любой указатель, который вы передадите, будет меньше значить для другого процесса. это один из огромных бонусов процессов.

Если вы хотите обмениваться данными между процессами, вам нужно будет использовать некоторую форму Межпроцессное взаимодействие (IPC) .

Есть несколько способов сделать IPC под windows . На мой взгляд, самый универсальный метод - это использование сокетов. Сокеты дают вам преимущество, заключающееся в том, что вы можете разделять машины, на которых выполняются процессы A и B, и при этом получать требуемую функциональность. Точно так же ничто не может остановить оба процесса, запущенных на одной машине. Гибкость, которую он обеспечивает, очень полезна.

Итак, если вы выбираете метод IPC на основе сокетов, тогда вы фактически делаете Удаленный вызов процедур (RPC) .

Как вы, вероятно, можете себе представить, существует множество различных способов выполнения RPC. Вы можете использовать DCOM или Corba . Raknet - сторонняя библиотека, поддерживающая RPC. Есть также множество других решений. Я настоятельно рекомендую провести множество исследований по этому вопросу. Ссылки и ключевые слова, которые я вам предоставил, должны послужить хорошей отправной точкой:)

3 голосов
/ 04 ноября 2010

Вы можете просто экспортировать функцию, используя __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 голосов
/ 04 ноября 2010

Если вы хотите, чтобы оба процесса использовали одну и ту же функцию, поместите функцию в DLL и свяжите эту DLL с обоими процессами.Каждый процесс имеет свое собственное адресное пространство, поэтому адрес в одном процессе может вообще не работать в другом процессе, и даже если он «работает», он будет указывать на что-то совершенно другое.

Хотя выпринимая / передавая смещение в область отображения памяти на родительской стороне, я не вижу соответствующего кода для сопоставления той же области и добавления его базы к указателю при попытке доступа к нему на стороне клиента.

Visual C ++ имеет тип указателя __based, который может немного упростить это.

...