2016-12-01 72 views
-1

形勢被稱爲

外部庫(LibraryExternal),我不能改變LibraryA的調用LoadLibrary。在它成功加載後,它會調用一個導出的函數AExport,它返回一個指向ClassA的指針,該指針是一個靜態實例。在AExport返回之前,它也通過稱爲LibraryB的LoadLibrary加載一個庫。在成功加載後,它調用一個導出的函數BExport,該函數繼而返回一個指向靜態實例ClassB的指針。

重要

LibraryA的是一個C++ DLL與vs2012 XP工具編譯和LibraryB是一個C++/CLI DLL也與vs2012 XP工具編譯。

爲了理解AExport和BExport返回的指針,所有庫都共享一些只定義ClassA和ClassB需要派生的庫。它們只不過是存根(stub)而已,在這個問題中並不重要(只有純虛函數,沒有字段,ctor/dtor也沒有做任何事情)。

結果

當LibraryExternal被通過程序退出卸載,它調用LibraryA的FreeLibrary則。這成功地調用ClassA的析構函數,然後釋放庫LibraryB。但是ClassB的析構函數絕不會以某種方式運行。

所需的結果

有無ClassB的析構函數運行

ClassA.h

#include <StubA.h> 

class StubB; 

class ClassA: public StubA 
{ 
    public: 
     ClassA(); 
     ~ClassA(); 

     bool Initialize(); 

     static ClassA &GetInstance() 
     { 
      static ClassA INSTANCE; 

      return INSTANCE; 
     } 

    private: 
     ClassA(ClassA const &); 
     void operator=(ClassA const&); 

     HMODULE wrapperModule; 
     StubB *wrapperPlugin; 
}; 

ClassA.cpp

#include "ClassA.h" 

#include <Windows.h> 

// typedef WrapperPlugin *(*WrapperPluginInitType)(); This is normally in shared library 

static const wchar_t *WRAPPER_MODULE_NAME = L"LibraryB.dll"; 
static const char *WRAPPER_MODULE_INIT_FUNCTION_NAME = "BExport"; 

ClassA::ClassA() : 
    wrapperModule(NULL), 
    wrapperPlugin(NULL) 
{ 

} 

ClassA::~ClassA() 
{ 
    if (this->wrapperModule != NULL) 
    { 
     FreeLibrary(this->wrapperModule); 
    } 
} 

bool CSharpBridge::Initialize() 
{ 
    this->wrapperModule = LoadLibraryW(WRAPPER_MODULE_NAME); 
    if (this->wrapperModule == NULL) 
    { 
     return false; 
    } 

    WrapperPluginInitType wrapperPluginInit = reinterpret_cast<WrapperPluginInitType>(GetProcAddress(this->wrapperModule, WRAPPER_MODULE_INIT_FUNCTION_NAME)); 
    if (wrapperPluginInit == NULL) 
    { 
     return false; 
    } 

    this->wrapperPlugin = wrapperPluginInit(); 
    if (this->wrapperPlugin == NULL) 
    { 
     return false; 
    } 

    return true; 
} 

extern "C" 
{ 
    __declspec(ddlexport) StubA *AExport() 
    { 
     if (!ClassA::GetInstance().Initialize()) 
     { 
      return NULL; 
     } 

     return &ClassA::GetInstance(); 
    } 
} 

ClassB.h

#include <StubB.h> 

class ClassB : public StubB 
{ 
    public: 
     ClassB(); 
     ~ClassB(); 

     static ClassB &GetInstance() 
     { 
      static ClassB INSTANCE; 

      return INSTANCE; 
     } 

    private: 
     ClassB (ClassB const &); 
     void operator=(ClassB const&); 
}; 

ClassB.cpp

#include "ClassB.h" 

#include <Windows.h> 
#include <iostream> 
#include <fstream> 

ClassB::ClassB() 
{ 
    std::ofstream myfile; 
    myfile.open("C:\\Users\\USERNAME\\Desktop\\test1.txt"); 
    myfile << "ClassB::ClassB\r\n"; 
    myfile.close(); 
} 

ClassB::~ClassB() 
{ 
    std::ofstream myfile; 
    myfile.open("C:\\Users\\USERNAME\\Desktop\\test3.txt"); 
    myfile << "ClassB::~ClassB\r\n"; 
    myfile.close(); 
} 

extern "C" 
{ 
    __declspec(dllexport) StubB *WrapperInit() 
    { 
     std::ofstream myfile; 
     myfile.open("C:\\Users\\USERNAME\\Desktop\\test2.txt"); 
     myfile << "WrapperInit\r\n"; 
     myfile.close(); 

     return &ClassB::GetInstance(); 
    } 
} 

現在我知道100%的把握認爲ClassA的構造函數/析構函數調用,由於一些LibraryExternal功能,這給我一些文本確認。我似乎得到了生成test1.txt和test2.txt。但不是test3.txt。

在此之後,我仍然需要創建一個託管的引用LibraryC這是一個C#DLL和'破壞',當ClassB被破壞。

+0

至少解釋你爲什麼downvoted所以我可以做得更好下一次.. – Neijwiert

+0

嗯,我可以看到如何發生。當你要求志願者投入他們的空閒時間來幫助你時,最起碼的禮貌是發佈可以編譯和運行的代碼來重現問題。此代碼不會編譯,也不會運行。相當簡單的照顧,只是先編譯和運行它自己。 –

回答

0

似乎無法在從非託管庫管理的庫上使用FreeLibrary。由於託管庫將啓動非託管庫對其一無所知的AppDomain。 AppDomain保持庫活着,因此析構函數從未運行。請參閱this的答案。

調用一些從非託管到託管的東西仍然需要特別注意,因爲不這樣做會導致異常:0xC0020001:字符串綁定無效!見this。我所做的解決這個問題的方法是在ClassB作用域中創建一個靜態實例,並使用ClassB :: GetInstance中的new運算符對其進行初始化。否則它根本不會被初始化。然後我做了一個函數ClassB :: CleanUp,我在其中刪除它。然而,使用#pragma managed(push,off)和#pragma managed(pop)標記整個類(頭文件和源文件)不受管理非常重要。

要仍能夠調用託管方法/類,必須在源文件中使用#pragma managed(push,on)和#pragma managed(pop)包圍的函數。然後你可以從非託管類調用這個函數。這對我來說還是很奇怪,因爲這個功能也是被管理的?