从 C++ 调用 C++/CLI 函数;图书馆

发布于 2024-08-18 06:29:52 字数 2353 浏览 4 评论 0原文

我需要将本机 C++ 库集成到 C# 项目中。现在,在这个 C++ 库中,有一个带有虚函数的类,我需要在 C++/CLI 中继承该类。 因此,我在 C++/CLI 中编写了类似“

class C++CliClass : public C++Class
{ 
  C++CliClass(Callback callback) { iCallback = callback; }
  virtual VirualFunctionCallFromC++(int x, int y, int z, SomeClass *p)
  { 
     // I need to call C++/CLI here
     iCallback(x, y, z, p);
  }

 private:
   Callback iCallback;
}

I defined the callback function as:
typedef int (__cdecl *Callback)(int x, int y, int z, SomeClass *p);

The idea is now that C++ library calls the virtual function of the C++Cli 
    class which on his turn calls the call back which gets me hopefully into C#.

// This delegate definition is needed to setup the callback for the C++ class
delegate int CallbackDelegate(int x, int y, int z, SomeClass *p);

So now I defined a managed C++/CLI class
public ref class GCClass
{
  public: 
    delegate <Byte>^ GetDataDelegate();
    GCClass(GetData^ getDataDelegate) { iGetDataDelegate = getDataDelegate };

  private:
    GetDataDelegate ^iGetDataDelegate;
    int GetData(int x, int y, int z, SomeClass *p)
    {
       // call delegate into C#
       <Byte>^ data = iGetDataDelegate->Invoke();
    }
  public:
    void SomeFunctionWhichEventuallyCallsC++Libary
    {
       // create a delegate for the method that will call the C# delegate
       CallbackDelegate ^d = gcnew CallbackDelegate(this, &GCClass::GetData);
       IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);

       // Install in the C++ class
       C++CliClass(del.ToPointer());

       // Setup the C++ library and install my C++ class into the library
       SomeObjectOfTheLibrary->Install(&C++CliClass);
       SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#

       // The delegate is no longer needed anymore
    }

直到这里的代码”之类的内容。所以我希望实现的是,有人可以调用我的托管 C++/CLI 类的方法,该类使用本机 C++ 库来完成他的工作。 C++ 库轮流调用 C++/CLI 回调,最后调用 C# 委托。现在最后的问题是:在调试模式下一切正常。然而,在发布模式下,有时会抛出 AccesException,或者有时应用程序会挂起。我怀疑这与 C++/CLI 和 C++ 的不同调用约定有关。例如,我观察到第二次调用回调时 iCallback 的值与第一次调用时不同。然而,对于所有接下来的调用,iCallback 的值不再改变。我希望 iCallback 值应该始终相同,但我不确定,因为我不知道框架内部如何工作才能从 C++ 调用委托。我还尝试使用 [UnmanagedFunctionPointer(Cdecl)] 定义 CallbackDelegate 的调用约定。我尝试了所有选项,但没有结果:我总是以异常结束,或者应用程序永远挂起。有人能给我提示一下可能出了什么问题吗?

I need to integrate a native C++ library into a C# project. Now in this C++ library there is class with virtual functions that I need to inherit from in C++/CLI.
So in C++/CLI I wrote someting like

class C++CliClass : public C++Class
{ 
  C++CliClass(Callback callback) { iCallback = callback; }
  virtual VirualFunctionCallFromC++(int x, int y, int z, SomeClass *p)
  { 
     // I need to call C++/CLI here
     iCallback(x, y, z, p);
  }

 private:
   Callback iCallback;
}

I defined the callback function as:
typedef int (__cdecl *Callback)(int x, int y, int z, SomeClass *p);

The idea is now that C++ library calls the virtual function of the C++Cli 
    class which on his turn calls the call back which gets me hopefully into C#.

// This delegate definition is needed to setup the callback for the C++ class
delegate int CallbackDelegate(int x, int y, int z, SomeClass *p);

So now I defined a managed C++/CLI class
public ref class GCClass
{
  public: 
    delegate <Byte>^ GetDataDelegate();
    GCClass(GetData^ getDataDelegate) { iGetDataDelegate = getDataDelegate };

  private:
    GetDataDelegate ^iGetDataDelegate;
    int GetData(int x, int y, int z, SomeClass *p)
    {
       // call delegate into C#
       <Byte>^ data = iGetDataDelegate->Invoke();
    }
  public:
    void SomeFunctionWhichEventuallyCallsC++Libary
    {
       // create a delegate for the method that will call the C# delegate
       CallbackDelegate ^d = gcnew CallbackDelegate(this, &GCClass::GetData);
       IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);

       // Install in the C++ class
       C++CliClass(del.ToPointer());

       // Setup the C++ library and install my C++ class into the library
       SomeObjectOfTheLibrary->Install(&C++CliClass);
       SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#

       // The delegate is no longer needed anymore
    }

Until here the code. So what I was hoping to achieve is that someone can call a method of my managed C++/CLI class which uses a native C++ library to do his stuff. The C++ library calls on his turn the C++/CLI callback and finally a C# delegate is called. Now finally the question: everything goes fine in debug mode. In release mode however sometimes an AccesException is thrown or sometimes the application just hangs. I suspect that it has something to do with different calling conventions for C++/CLI and C++. For example I observed that the second time the callback is called the value of iCallback is different from the first time it was called. However for all next calls the value of iCallback does not change anymore. I would expect that the iCallback value should be always the same but I'm not sure because I don't know how the framework internally works to be able to call a delegate from C++. I also tried to define the calling convention of the CallbackDelegate with [UnmanagedFunctionPointer(Cdecl)]. I tried all options but had no result: I always end up in an exception or the application hangs forever. Can someone give me a hint of what might be wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

菊凝晚露 2024-08-25 06:29:52

确保委托在仍然需要时不会被垃圾回收。
在 C++CliClass 类中,您可以添加 CallbackDelegate 类型的成员并将其设置为 d。
如果 C++CliClass 的实例仅在执行 SomeFunction 期间存在。函数末尾的 GC.KeepAlive(d) 可能就足够了。

也许更简单:在 C++CliClass 中定义一个 gcroot类型的成员;然后直接在 VirtualFunction 中调用该成员的 GetData 函数,而不需要委托。

Make sure the delegate is not garbage collected when it's still needed.
In class C++CliClass you could add a member of type CallbackDelegate and set it to d.
If the instance of C++CliClass only exists during execution of SomeFunction.. GC.KeepAlive(d) at the end of the function might be sufficient.

Perhaps even simpler: in C++CliClass define a memeber of type gcroot<GCClass^> then directly call the GetData function on this memeber in VirtualFunction without the need for a delegate.

安稳善良 2024-08-25 06:29:52

上面代码的问题之一是 d 是托管引用,这意味着它可以在运行时移动。这反过来将使您的回调指针无效。

为了将委托传递给本机代码,您需要使用 GCHandle::Alloc 告诉垃圾收集器不要移动它:

   CallbackDelegate^ d = gcnew CallbackDelegate(this, &GCClass::GetData);

   // As long as this handle is alive, the GC will not move or collect the delegate
   // This is important, because moving or collecting invalidate the pointer
   // that is passed to the native function below
   GCHandle delegate_handle = GCHandle::Alloc(d);

   IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);

   C++CliClass native(del.ToPointer());

   SomeObjectOfTheLibrary->Install(&native);
   SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#

   // Release the handle
   delegate_handle.Free();

One of the problems with your code above is that d is a managed reference, which means that it can be moved around at runtime. This in turn will invalidate your callback pointer.

In order to pass the delegate to native code, you need to tell the garbage collector not to move it, using GCHandle::Alloc:

   CallbackDelegate^ d = gcnew CallbackDelegate(this, &GCClass::GetData);

   // As long as this handle is alive, the GC will not move or collect the delegate
   // This is important, because moving or collecting invalidate the pointer
   // that is passed to the native function below
   GCHandle delegate_handle = GCHandle::Alloc(d);

   IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);

   C++CliClass native(del.ToPointer());

   SomeObjectOfTheLibrary->Install(&native);
   SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#

   // Release the handle
   delegate_handle.Free();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文