C# 调用C++/C++;图书馆
我需要将一个本地C++库集成到C语言项目中。现在在这个C++库中,有一个类,我需要从C++中继承虚拟函数。 因此,在C++/CLI中,我编写了如下内容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) {
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成员。类。它也可以工作,而且确实更干净:没有委托,所以不需要担心调用约定和垃圾收集问题。我将使用此解决方案。感谢大家帮助我。