当函数 returns 指针指向抽象 class 时,将 "C++ dll" 包装在 "C++/CLI" 中

Wrapping "C++ dll" in "C++/CLI" when function returns pointer to abstract class

我有 C++ dll: UnmanagedCode.h 看起来像:

#include "stdafx.h"
struct Class1
{
 public: virtual void method() = 0;
};
extern "C" __declspec(dllimport) Class1* Create_function();

UnmanagedCode.cpp 看起来像:

#include "stdafx.h"
#include "UnmanagedCode.h"
class Class2 : Class1
{
 public: void method(){}
};

Class1* Create_function()
{
 Class2* c2 = new Class2(); // I don't care about free memory for this  example
 Class1* c1 = (Class1*)c2;
 return c1;
};

我有 c++/cli 管理 class:

    #include "Library.h"
    #include "UnmanagedCode.h"
    typedef Class1* (*Createfunction)();
    namespace CLIWrapper
    {
    public ref class ManagedClI
    {
      private:
        Class1* cl1;
      public:
        ManagedClI(){}
        void Create()
        {   
            //some usual routine for loading c++ library with Library class
            String ^path = "path to the library.dll"; // just to show
            using System::Runtime::InteropServices::Marshal;
            const char* cpath = (const char*)(Marshal::StringToHGlobalAnsi(path)).ToPointer();
            Library loader;
            loader.load((string)cpath, false);
            Marshal::FreeHGlobal(System::IntPtr((void*)cpath)); 
            Createfunction hDet = (Createfunction)loader.getProcAddress("Create_function"); 
            cl1 = hDet();
            cl1->method();  // if I call cl1->method() here it works perfect!!      
        }

        void SomeFunction()
        {           
           cl1->method();    //but if I call cl1->method() here it throws an error!!!
        }
    };
    }

我在我的 C# 应用程序中使用 ManagedClI class,类似于:

CLIWrapper.ManagedClI object = new CLIWrapper.ManagedClI();
object.Create();
object.SomeFunction(); // <- this causes an error

object.SomeFunction() 导致错误:在调用 cl1->method() 时试图读取或写入受保护的内存。 但同时 cl1->method()Object.Create().

中正常工作

我认为我在包装时做错了什么 Create_function()。 谁能推荐一下?

您的 Library loader 不仅仅是一个加载器。它是保持 DLL 加载的 CLI 对象。当对它的最后一次引用消失并被清理时,DLL 被卸载。

抽象 class 的虚函数 table 存在于该 DLL 中,它指向的函数也是如此。当 DLL 被卸载时,那个虚函数 table 变得无效,并且试图调用该方法将是未定义的行为。

要初步解决此问题,请将 Library 对象存储在 ManagedClI class 中,而不是作为局部变量。