C# 调用C++/C++;图书馆

C# 调用C++/C++;图书馆,c#,c++-cli,C#,C++ Cli,我需要将一个本地C++库集成到C语言项目中。现在在这个C++库中,有一个类,我需要从C++中继承虚拟函数。 因此,在C++/CLI中,我编写了如下内容 class C++CliClass : public C++Class { C++CliClass(Callback callback) { iCallback = callback; } virtual VirualFunctionCallFromC++(int x, int y, int z, SomeClass *p) {

我需要将一个本地C++库集成到C语言项目中。现在在这个C++库中,有一个类,我需要从C++中继承虚拟函数。 因此,在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++类:公共C++类
{ 
C++CliClass(回调){iCallback=Callback;}
C++中的虚拟虚拟虚拟函数调用(int x,int y,int z,SomeClass*p)
{ 
//我需要在这里调用C++/CLI
iCallback(x,y,z,p);
}
私人:
回叫iCallback;
}
我将回调函数定义为:
typedefint(uu cdecl*回调)(intx,inty,intz,SomeClass*p);
现在的想法是C++库调用C++ CLI的虚函数
轮到他回电话给我,希望我能进入C。
//这个委托定义需要为C++类设置回调
委托int CallbackDelegate(intx,inty,intz,SomeClass*p);
现在我定义了一个托管C++/CLI类
公共参考类
{
公众:
委托^GetDataDelegate();
GCClass(GetData^getDataDelegate){iGetDataDelegate=getDataDelegate};
私人:
GetDataDelegate^iGetDataDelegate;
intgetdata(intx,inty,intz,SomeClass*p)
{
//将委托调用到C中#
^数据=IGETDATADegate->Invoke();
}
公众:
无效某些函数,这些函数实际上调用了SC++库
{
//为将调用C#委托的方法创建委托
CallbackDelegate ^d=gcnewcallbackdelegate(this,&GCClass::GetData);
IntPtr del=System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);
//安装在C++类中
C++CliClass(del.ToPointer());
//设置C++库并将C++类安装到库中
someobjectoflibrary->Install(&C++CliClass);
THEARBAREY-> DOMTEMITION()//将调用C++虚拟函数,并在C语言中结束。
//不再需要该委托
}

<> >代码。所以我希望实现的是,某人可以调用我的托管C++/CLI类的方法,使用本地C++库来完成他的操作。C++库在他轮流中调用C++/CLI回调,最后调用一个C代表。现在问题是:在调试模式下,一切都会变好。有时会抛出Access异常,有时甚至会挂起应用程序。我怀疑它与C++、CLI和C++的不同调用约定有关。例如,我观察到第二次调用回调的值是ICLBACK的值与第一次调用时的值不同。ICALBACK的E不再改变。我希望ICALBACK值应该总是相同的,但我不确定,因为我不知道框架内部如何工作,以便能够调用C++的委托。我还尝试用[unMaundActudioPosiple(CDECL)定义CALBACK委托的调用约定]。。我尝试了所有选项,但没有结果:我总是出现异常或应用程序永远挂起。有人能告诉我可能有什么问题吗?

确保在仍然需要代理时不会对其进行垃圾收集。 在C++CliClass类中,可以添加CallbackDelegate类型的成员并将其设置为d。 如果C++CliClass的实例仅在执行某个函数期间存在,则函数末尾的..GC.KeepAlive(d)就足够了


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

上面代码的一个问题是,
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();

Henrik的答案要好得多,委托对象不需要固定方法,该方法启动一个新线程。我尝试了Bojan建议,效果很好。调用是为了从C++/CLI调用C#委托。我可以采取其他方法来执行此操作吗?@nobugz
Invoke
不会启动新线程。对委托调用
Invoke
与执行
del()完全相同实际上,如果委托被传递到本机代码,则需要进行钉扎,就像指针从托管代码传递到本机代码时一样。它通常也是最容易的解决方案。当然,当解决方案不涉及委托时,就不需要钉扎。@我也尝试过亨利克建议在C++中使用GCROOT成员。类。它也可以工作,而且确实更干净:没有委托,所以不需要担心调用约定和垃圾收集问题。我将使用此解决方案。感谢大家帮助我。