Ну, я использую следующий подход.
В DLL, которая впрыскивается, создать общий раздел, например:
#pragma data_seg(".MyShared")
LPTHREAD_START_ROUTINE g_lpMyFunc = NULL;
#pragma data_seg()
#pragma section(".MyShared", read, write, shared)
Общий раздел переменной g_lpMyFunc
затем инициализируется внутри DllMain
так:
BOOL APIENTRY DllMain(HMODULE, DWORD dwReasonForCall, LPVOID)
{
if (NULL != GetModuleHandle(_T("MyApp.exe")))
{
if (DLL_PROCESS_ATTACH == dwReasonForCall)
{
g_lpMyFunc = (LPTHREAD_START_ROUTINE)&MyFunc;
}
else if (DLL_PROCESS_DETACH == dwReasonForCall)
{
g_lpMyFunc = NULL;
}
}
return TRUE;
}
Этот код делает следующее. Вызов функции GetModuleHandle
пытается получить дескриптор исполняемого модуля MyApp. Если это удается, оно возвращает значение, отличное от NULL, и это означает, что выведенная DLL DllMain
DLL вызывается из удаленного процесса. Если это так, адрес MyFunc
сохраняется в общей переменной g_lpMyFunc
. И если DLL отсоединена от процесса (когда он завершается, например), я устанавливаю g_lpMyFunc
в NULL, чтобы не было возможности вызвать функцию по удаленному адресу, которого нет.
Я затем создать внешнюю функцию MyFuncExtern
, которая вызывает MyFunc
в удаленном процессе, как это:
extern "C" __declspec(dllexport) bool __cdecl MyFuncExtern(HANDLE hProcess)
{
if (NULL == g_lpMyFunc)
{
return false;
}
return NULL != CreateRemoteThread(hProcess, NULL, 0, g_lpMyFunc, NULL, 0, NULL);
}
Это очень упрощенная версия, но она показывает основную концепцию: если g_lpMyFunc
не NULL, он создает удаленный поток в hProcess
(как и в вашем коде), который вызывает функцию по адресу, указанному g_lpMyFunc
.
Есть некоторые ограничения на этой функции, хотя с CreateRemoteThread
принимает только один аргумент для функции дистанционного управления (вы может пройти больше, однако это потребуется значительно более сложный подход), и если вам нужно возвращать значение вы будете придется дождаться завершения удаленного потока и получить его код выхода, то есть DWORD
.
Этот подход хорош при написании функций инициализации/неинициализации и, более того, он отлично работает для управляемых DLL с C++/CLI.
И, конечно, вы можете использовать любое другое хранилище данных перекрестного процесса для сохранения указателей функций. Хорошим примером являются файлы с отображением памяти.