Мне приходилось взаимодействовать с устаревшим приложением, вероятно, в той же ситуации, что и вы.Я нашел хакерский способ получить функциональность DllMain в сборке CLR.К счастью, это не так уж сложно.Для этого требуется дополнительная библиотека DLL, но не требуется развертывание дополнительной библиотеки DLL, чтобы вы могли иметь парадигму «поместите DLL в этот каталог, и приложение загрузит ее».
Во-первых, вы создаете простую обычную C ++ DLL, которая выглядит следующим образом:
dllmain.cpp:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "resource.h"
extern void LaunchDll(
unsigned char *dll, size_t dllLength,
char const *className, char const *methodName);
static DWORD WINAPI launcher(void* h)
{
HRSRC res = ::FindResourceA(static_cast<HMODULE>(h),
MAKEINTRESOURCEA(IDR_DLLENCLOSED), "DLL");
if (res)
{
HGLOBAL dat = ::LoadResource(static_cast<HMODULE>(h), res);
if (dat)
{
unsigned char *dll =
static_cast<unsigned char*>(::LockResource(dat));
if (dll)
{
size_t len = SizeofResource(static_cast<HMODULE>(h), res);
LaunchDll(dll, len, "MyNamespace.MyClass", "DllMain");
}
}
}
return 0;
}
extern "C" BOOL APIENTRY DllMain(HMODULE h, DWORD reasonForCall, void* resv)
{
if (reasonForCall == DLL_PROCESS_ATTACH)
{
CreateThread(0, 0, launcher, h, 0, 0);
}
return TRUE;
}
Обратите внимание на создание потока.Это должно сделать Windows счастливой, потому что вызов управляемого кода в точке входа DLL - нет-нет.
Далее, вы должны создать эту функцию LaunchDll, код которой приведен выше.Это идет в отдельном файле, потому что он будет скомпилирован как управляемый модуль кода C ++.Для этого сначала создайте файл .cpp (я назвал его LaunchDll.cpp).Затем щелкните правой кнопкой мыши по этому файлу в вашем проекте и в Свойства конфигурации -> C / C ++ -> Общее изменить Общедоступную поддержку RunTime на Общедоступную поддержку RunTime (/ clr) .У вас не может быть исключений, минимальной перестройки, проверок во время выполнения и, возможно, некоторых других вещей, о которых я забыл, но компилятор расскажет вам об этом.Когда компилятор жалуется, отследите, какие настройки значительно отличаются от настроек по умолчанию, и измените их в файле LaunchDll.cpp * только 1032 * .
LaunchDll.cpp:
#using <mscorlib.dll>
// Load a managed DLL from a byte array and call a static method in the DLL.
// dll - the byte array containing the DLL
// dllLength - the length of 'dll'
// className - the name of the class with a static method to call.
// methodName - the static method to call. Must expect no parameters.
void LaunchDll(
unsigned char *dll, size_t dllLength,
char const *className, char const *methodName)
{
// convert passed in parameter to managed values
cli::array<unsigned char>^ mdll = gcnew cli::array<unsigned char>(dllLength);
System::Runtime::InteropServices::Marshal::Copy(
(System::IntPtr)dll, mdll, 0, mdll->Length);
System::String^ cn =
System::Runtime::InteropServices::Marshal::PtrToStringAnsi(
(System::IntPtr)(char*)className);
System::String^ mn =
System::Runtime::InteropServices::Marshal::PtrToStringAnsi(
(System::IntPtr)(char*)methodName);
// used the converted parameters to load the DLL, find, and call the method.
System::Reflection::Assembly^ a = System::Reflection::Assembly::Load(mdll);
a->GetType(cn)->GetMethod(mn)->Invoke(nullptr, nullptr);
}
Теперь для действительно сложной части.Вы, вероятно, заметили загрузку ресурса в dllmain.cpp: launcher ().Что он делает, так это извлекает вторую DLL, которая была вставлена в качестве ресурса в создаваемую здесь DLL.Для этого создайте файл ресурса, выполнив правой кнопкой мыши -> Добавить -> Новый предмет -> Visual C ++ -> Ресурс -> Файл ресурсов (.rc) вещь.Затем вам нужно убедиться, что в файле есть строка типа:
resource.rc:
IDR_DLLENCLOSED DLL "C:\\Path\\to\\Inner.dll"
.(Хитро, да?)
Осталось только создать эту Inner.dll сборку.Но у вас уже есть это!Это то, что вы пытались запустить с помощью своего старого приложения.Просто убедитесь, что вы включили класс MyNamespace.MyClass в метод public void DllMain () (конечно, вы можете вызывать эти функции как хотите, это просто значения, жестко закодированные вdllmain.cpp: launcher () выше.
Итак, в заключение, приведенный выше код берет существующую управляемую DLL, вставляет ее в ресурс неуправляемой DLL, которая при подключении к процессу загружаетуправлять DLL из ресурса и вызывать в нем метод.
Оставить читателю в качестве упражнения лучшую проверку ошибок, загружать разные DLL для режима отладки и выпуска и т. д., вызывая замену DllMain с одинаковыми аргументамипередается в реальный DllMain (пример делает это только для DLL_PROCESS_ATTACH) и жестко кодирует другие методы внутренней DLL во внешней DLL как методы прохода.