【问题标题】:Wrapping "C++ dll" in "C++/CLI" when function returns pointer to abstract class当函数返回指向抽象类的指针时,在“C++/CLI”中包装“C++ dll”
【发布时间】:2015-03-16 13:20:47
【问题描述】:

我有 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 托管类:

    #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# 应用程序中使用 ManagedCI 类,类似于:

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

object.SomeFunction() 导致错误:在调用 cl1-&gt;method() 时尝试读取或写入受保护的内存。 但同时cl1-&gt;method() 正常工作在Object.Create()

我认为我在包装 Create_function() 时做错了什么。 任何人都可以提出一些建议吗?

【问题讨论】:

  • 一个猜测(我不是 C++/cli C++ C# 互操作专家),但我要调查的是,如果 loader 超出范围会导致 Library 对象卸载 dll。哪个卸载虚拟功能表,并导致您的问题?它至少可以解释症状,并且很容易检查:将 Library 对象存储在您的 ManagedCLI 类中而不是本地。
  • @Yakk 你是对的!非常感谢!
  • 另外,永远不要使用Marshal::StringToHGlobalAnsi。 C++/CLI 带有 marshal_as&lt;std::string&gt; 帮助模板,它的工作效率提高了一千倍。
  • @BenVoigt 实际上这只是举例,但无论如何,谢谢 =) 但 Loader 是真实的。
  • 本机代码永远不需要太多帮助来破坏堆,当它爆炸时向我们展示堆栈跟踪对于停止猜测非常重要。您在代码中犯了一个错误,C++/CLI 编译器无法判断这些声明是针对本机代码的,并且使用 __cdecl 调用约定。您需要用#pragma managed(push, off) 和#pragma managed(pop) 包装#include 和typedef。

标签: c# visual-c++ c++-cli clr wrapper


【解决方案1】:

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

抽象类的虚函数表和它指向的函数一样存在于该 DLL 中。当 DLL 被卸载时,该虚函数表变得无效,并且尝试调用该方法将是未定义的行为。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 2012-02-02
    相关资源
    最近更新 更多