分类: 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 =你的 DLL 包含调用者,该调用者使用托管代码以及 DLL 输出或者托管入口点,修改方式如下:__crt_dll_terminate(); return hr; } STDAPI DllUnregisterServer(void) { if ( !( __crt_dll_initialize() ) ) { return E_FAIL; } // 在这里调用注销代码 HRESULT hr = __crt_dll_terminate(); return hr; }
// 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; }