2016-12-01 76 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)包围的函数。然后你可以从非托管类调用这个函数。这对我来说还是很奇怪,因为这个功能也是被管理的?