第二个dll中的静态实例的破坏者未被调用

Destructor of static instance in second dll not being called

本文关键字:调用 破坏者 静态 dll 第二个 实例      更新时间:2023-10-16

情况

我无法在Librarya上更改loadLibrary的外部库(Library External)。成功加载它后,它调用导出的函数AEXPORT,该功能将指针返回ClassA,这是一个静态实例。在AEXPORT返回之前,它也通过LoadLibrary加载库,称为LibraryB。在成功加载后,它调用导出的函数bexport,然后将指针返回到静态实例classb。

重要

LibraryA是一个C DLL,使用VS2012 XP工具编译,LibraryB是C /CLI DLL,也使用VS2012 XP工具编译。

所有库都共享其他一些库,这些库仅定义了Clasta和ClassB需要从哪些库中得出的,以了解Aexport和Bexport返回的指针。它们只不过是存根,在这个问题中无关紧要(只有纯虚拟功能,没有字段,并且在ctor/dtor中什么也没有做)。

结果

当Library External通过程序退出卸载时,它会在LibraryA上调用Freelibrary。这成功称为" classa"的驱动器,后者又释放了图书馆库。但是,ClassB的破坏者永远不会以某种方式运行。

所需结果

有classB destructor run

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::ClassBrn";
    myfile.close();
}
ClassB::~ClassB()
{
    std::ofstream myfile;
    myfile.open("C:\Users\USERNAME\Desktop\test3.txt");
    myfile << "ClassB::~ClassBrn";
    myfile.close();
}
extern "C"
{
    __declspec(dllexport) StubB *WrapperInit()
    {
        std::ofstream myfile;
        myfile.open("C:\Users\USERNAME\Desktop\test2.txt");
        myfile << "WrapperInitrn";
        myfile.close();
        return &ClassB::GetInstance();
    }
}

现在,我100%确定了Classa ctor/dtor被称为classa ctor/dtor,这是由于某些库外部功能提供了一些文本确认。而且我似乎已经获得了test1.txt和test2.txt生成的。但不是test3.txt。

之后,我仍然需要创建对c#dll和"破坏" classB被破坏时的托管引用。

看来,您无法在不受管理的库管理的库上使用Freelibrary。由于托管库将启动非管理图书馆对此一无所知的应用程序。AppDomain使图书馆保持活力,因此毁灭者从未运行过。看到此答案。

调用未管理到托管的东西仍然需要特别注意,因为不这样做会导致例外:0xc0020001:字符串绑定无效!看到这个。我为解决该问题所做的工作是在ClassB范围内具有静态实例,并使用ClassB :: getInstance中的新操作员初始化它。否则,它根本不会初始化。然后,我将classB ::清理删除。但是,重要的是用#pragma托管(推送,关闭)和#Pragma Managed(POP)标记整个类(标题和源文件)。

要仍然能够调用托管方法/类,您必须在源文件中制作一个函数,该函数被#pragma托管(push,on)和#pragma Managed(POP)包围。然后,您可以从非托管类调用此功能。这对我来说仍然很奇怪,因为该功能也是管理的吗?