分类: C/C++
2008-04-01 09:02:27
修改使用DLL的代码部分,进行手动初始化
转换成混合模式之后,你必须修改使用DLL的代码部分,根据你的DLL实现方式进行手动初始化:
用 __declspec(dllexport) 输出且调用者无法使用托管代码的 DLL 的修改方法:
// init.cpp // 在 using namespace System 指令头之前添加这些头文件, // 或者在没有using namespace System 指令头的 .cpp 文件中添加它们 #include将下面代码添加到 DLL .def 文件的 “exports” 部分:#include <_vcclrit.h> // 在你调用任何该 DLL 中的东西之前调用该函数。 // 从多线程中调用才安全,并非引用安全,而是重入安全 extern "C" __declspec(dllexport) void __stdcall DllEnsureInit(void) { // 在这里什么也不要做,如果你需要额外的初始化步骤, // 创建带有构造函数的静态对象,在构造函数中完成初始化。 __crt_dll_initialize(); // 在这里什么也不要做。 } // 在整个进程彻底调用完该 DLL 后调用该函数。从多线程中调用才安全。 // 并非引用安全,而是重入安全。第一次调用将终止。 extern "C" __declspec(dllexport) void __stdcall DllForceTerm(void) { // 在这里什么也不要做,如果你需要额外的终止步骤, // Do nothing else here. If you need extra terminate steps, // 使用 atexit. __crt_dll_terminate(); // 在这里什么也不要做。 }
DllEnsureInit PRIVATE DllForceTerm PRIVATE
如果没有这两行,那么当你有两个 DLL 都输出函数时,链接到该 DLL 的应用程序将会出现链接错误。典型的错误是输出的函数名字相同。
在有多个DLL调用者时,每个调用者都可以和你 DLL 进行静态或动态链接。
// 代码段一
typedef void (__stdcall *pfnEnsureInit)(void);
typedef void (__stdcall *pfnForceTerm)(void);
{
// ... 初始化代码
HMODULE hDll=::GetModuleHandle("mydll.dll");
If(!hDll)
{
// 退出,返回,再没有什么要做的了
}
pfnEnsureInit pfnDll=( pfnEnsureInit) ::GetProcAddress(hDll,
"DllEnsureInit");
if(!pfnDll)
{
// 退出,返回,再没有什么要做的了
}
pfnDll();
// ... 更多的初始化代码
}
// 代码段二
{
// ... 终止代码
HMODULE hDll=::GetModuleHandle("mydll.dll");
If(!hDll)
{
// 退出,返回,再没有什么要做的了
}
pfnForceTerm pfnDll=( pfnForceTerm) ::GetProcAddress(hDll,
"DllForceTerm");
if(!pfnDll)
{
// 退出,返回,再没有什么要做的了
}
pfnDll();
// ... 更多的终止代码
}
基于 COM 的 DLL 的修改方法
修改 DllCanUnloadNow,DllGetClassObject,DllRegisterServer 和 DllUnregisterServer 输出函数的方法如下:
// 实现 DLL 输出
STDAPI DllCanUnloadNow(void)
{
HRESULT hrReturn=S_FALSE;
// Function as usual
// At this point hrReturn is S_OK if you can unload
if(hrReturn == S_OK)
{
__crt_dll_terminate();
}
return hrReturn;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
// 在这里什么也不要做。
__crt_dll_initialize();
// 像从前那样继续 DllGetClassObject
}
STDAPI DllRegisterServer(void)
{
if ( !( __crt_dll_initialize() ) )
{
return E_FAIL;
}
// 在这里调用注册代码
HRESULT hr =
__crt_dll_terminate();
return hr;
}
STDAPI DllUnregisterServer(void)
{
if ( !( __crt_dll_initialize() ) )
{
return E_FAIL;
}
// 在这里调用注销代码
HRESULT hr =
__crt_dll_terminate();
return hr;
}
你的 DLL 包含调用者,该调用者使用托管代码以及 DLL 输出或者托管入口点,修改方式如下:
// ManagedWrapper.cpp // 这个代码验证当使用 /NOENTRY 链接选项时,DllMain 没有被 Loader 自动调用。 // 它也检查某些 CRT 初始化函数。 #include#include #include #include #include #include "_vcclrit.h" #using using namespace System; public __gc class ManagedWrapper { public: static int minitialize() { int retval = 0; try { __crt_dll_initialize(); } catch(System::Exception* e) { Console::WriteLine(e); retval = 1; } return retval; } static int mterminate() { int retval = 0; try { __crt_dll_terminate(); } catch(System::Exception* e) { Console::WriteLine(e); retval = 1; } return retval; } }; BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved) { Console::WriteLine(S"DllMain is called..."); return TRUE; } /* DllMain */
#using#using "ijwdll.dll" using namespace System; int main() { int retval = 0; retval += ManagedWrapper::minitialize(); retval += ManagedWrapper::mterminate(); return retval; }