您的位置:首页 > 编程语言 > C语言/C++

如何在非托管C++中调用托管C#中的回调函数

2016-06-16 09:09 721 查看


如何在非托管C++中调用托管C#中的回调函数 [问题点数:40分,结帖人kndyc]

不显示删除回复 显示所有回复
显示星级回复 显示得分回复
只显示楼主

收藏





关注
kndyc
kndyc
等级:


结帖率:100%
楼主发表于: 2012-12-08 10:46:02

大家好,我刚刚接触.net,下面是msdn关于回调函数的解释
http://msdn.microsoft.com/zh-cn/library/843s5s5x(v=vs.100).aspx
问题是如何在非托管C++中调用托管C#中的回调函数,文章中没有说。

为了防止垃圾回收,我用HandleRef盯住了回调函数,当C#程序执行了

CallBack myCallBack = new CallBack(EnumReportApp.Report);

IntPtr ptr = Marshal.GetFunctionPointerForDelegate(myCallBack);

HandleRef hr = new HandleRef(myCallBack, ptr);

EnumWindows(hr, 0);

之后,myCallBack的指针被传递到了C++,假设指针的形参名是pCallBack,在C++的DLL中直接执行

pCallBack();

然后程序抛出了异常:“访问了受保护的内存区域”,继续运行抛出“回调函数被垃圾回收”。

我觉得应该是C++调用C#的函数指针的方法不对,请大家看看问题出在哪里?

更多0分享到:

相关主题推荐: c++ 指针 callback library 异常

相关帖子推荐:

在将 varchar 值 '交易案例' 转换成数据类型 int 时失败。

如何让其它程序报错

C#求一算法

请教一个指针的指针做形参的问题

C#获取JavaScript中的数据

菜鸟求助,c++指针问题

用c程序写的socket下载网页,有个url的网页死活下不下来

关于类默认构造函数的一些问题,求助。

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
回复次数:18



关注
wei_hang
我不是李白
等级:


#1 得分:0回复于:
2012-12-08 10:48:27

C++函数指针对应C#委托
CSDN投诉事项说明

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#2 得分:0回复于:
2012-12-08 11:00:53

C++函数指针对应C#委托,怎么对应呢?
【社区之星】朱燚:转战传统应用的弄潮儿

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
hdt


倦怠
等级:


#3 得分:10回复于:
2012-12-08 11:03:15

全部折叠全部展开 代码:全部 代码:多个 代码:Visual Basic 代码:C# 代码:Visual C++ 代码:J# 代码:JScript

Visual Basic

C#

Visual C++

J#

JScript

.NET Framework 开发人员指南

Callback 示例

请参见 发送反馈意见

该示例说明如何将委托传递给需要函数指针的非托管函数。委托是可以容纳对方法的引用的类,并且等效于类型安全函数指针或回调函数。

注意:

当您在调用内部使用委托时,公共语言运行库将在该调用的持续时间内防止对委托执行垃圾回收。但是,如果非托管函数存储该委托以供在该调用完成后使用,则您必须手动防止进行垃圾回收,直到非托管函数完成对该委托的使用为止。有关更多信息,请参见 HandleRef 示例和 GCHandle 示例。

Callback 示例使用以下非托管函数(这里同时显示其原始函数声明):

从 PinvokeLib.dll 导出的 TestCallBack。

复制代码

void TestCallBack(FPTR pf, int value);

从 PinvokeLib.dll 导出的 TestCallBack2。

复制代码

void TestCallBack2(FPTR2 pf2, char* value);

PinvokeLib.dll 是一个自定义非托管库,它包含前面列出的函数的实现。

在该示例中,LibWrap 类包含 TestCallBack 和 TestCallBack2 方法的托管原型。这两个方法都将委托作为参数传递给回调函数。该委托的签名必须与它所引用的方法的签名相匹配。例如,FPtr 和 FPtr2 委托的签名与 DoSomething 和 DoSomething2 方法的签名相同。

下面的代码示例的源代码由 .NET Framework 平台调用技术示例 提供。

声明原型

Visual Basic 复制代码

Public Delegate Function FPtr( ByVal value As Integer ) As Boolean

Public Delegate Function FPtr2( ByVal value As String ) As Boolean

Public Class LibWrap

' Declares managed prototypes for unmanaged functions.

Declare Sub TestCallBack Lib "..\LIB\PinvokeLib.dll" ( ByVal cb _

As FPtr, ByVal value As Integer )

Declare Sub TestCallBack2 Lib "..\LIB\PinvokeLib.dll" ( ByVal cb2 _

As FPtr2, ByVal value As String )

End Class 'LibWrap

C# 复制代码

public delegate bool FPtr( int value );

public delegate bool FPtr2( String value );

public class LibWrap

{// Declares managed prototypes for unmanaged functions.

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]

public static extern void TestCallBack( FPtr cb, int value );

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]

public static extern void TestCallBack2( FPtr2 cb2, String value );

}

调用函数

Visual Basic 复制代码

Public Class App

Public Shared Sub Main()

Dim cb As FPtr

cb = AddressOf App.DoSomething

Dim cb2 As FPtr2

cb2 = AddressOf App.DoSomething2

LibWrap.TestCallBack( cb, 99 )

LibWrap.TestCallBack2( cb2, "abc" )

End Sub 'Main

Public Shared Function DoSomething( ByVal value As Integer ) As Boolean

Console.WriteLine( ControlChars.CrLf + "Callback called with _

param: {0}", value )



End Function 'DoSomething

Public Shared Function DoSomething2( ByVal value As String ) As Boolean

Console.WriteLine( ControlChars.CrLf + "Callback called with _

param: {0}", value )



End Function 'DoSomething2

End Class 'App

C# 复制代码

public class App

{

public static void Main()

{

FPtr cb = new FPtr( App.DoSomething );

LibWrap.TestCallBack( cb, 99 );

FPtr2 cb2 = new FPtr2( App.DoSomething2 );

LibWrap.TestCallBack2( cb2, "abc" );

}

public static bool DoSomething( int value )

{

Console.WriteLine( "\nCallback called with param: {0}", value );



}

public static bool DoSomething2( String value )

{

Console.WriteLine( "\nCallback called with param: {0}", value );



}

}

请参见

概念

其他封送处理示例

平台调用数据类型

在托管代码中创建原型

发送反馈意见,就此主题向 Microsoft 发送反馈意见。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
hdt


倦怠
等级:


#4 得分:0回复于:
2012-12-08 11:06:53

不用把 委托转为 intptr,而是直接传委托

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#5 得分:0回复于:
2012-12-08 12:05:44

我是在C++的DLL中写了一个TestCallBack函数,但是在调用cb的时候抛出了异常,直接传委托也不行
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
zanfeng
1060151476
等级:


#6 得分:20回复于:
2012-12-08 13:23:14

可以的。

写了一个简单的例子

C# code

?
c#调用代码
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
zanfeng
1060151476
等级:


#7 得分:0回复于:
2012-12-08 13:24:12

C/C++ code

?
C/C++ code

?
def

C/C++ code

?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#8 得分:0回复于:
2012-12-08 13:38:18

我是这样做的,然后就抛出了异常。其实就是想要在C++里面调用C#的DoSomething函数

C/C++ code

?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
sp1234
以专业开发人员为伍
等级:


3

7

#9 得分:10回复于:
2012-12-08 13:42:09

引用 8 楼 kndyc 的回复:

我是这样做的,然后就抛出了

你是怎样做的?

要注意到,它(也许不经意间)使用了 public static 修饰符。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#10 得分:0回复于:
2012-12-08 14:03:28

原来没有加static,但是我用new给委托分配了空间,刚才加了public static修饰符还是一样的异常
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
zanfeng
1060151476
等级:


#11 得分:0回复于:
2012-12-08 19:46:50

引用 8 楼 kndyc 的回复:

我是这样做的,然后就抛出了异常。其实就是想要在C++里面调用C#的DoSomething函数

C/C++ code?1234void TestCallBack(void* pf, int value){ pf();}

DoSomething是带有参数的。

而你的函数指针是没有参数的。不异常都不正常。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
sp1234
以专业开发人员为伍
等级:


3

7

#12 得分:0回复于:
2012-12-08 20:19:47

引用 10 楼 kndyc 的回复:

原来没有加static,但是我用new给委托分配了空间,刚才加了public static修饰符还是一样的异常

什么意思?mew?

动态分配内存的东西,你不怕垃圾回收吗?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
sp1234
以专业开发人员为伍
等级:


3

7

#13 得分:0回复于:
2012-12-08 20:21:16

晕死!低级的系统是个死板的东西,你只能把纯粹静态方法作为参数。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#14 得分:0回复于:
2012-12-08 20:37:53

引用 11 楼 zanfeng 的回复:

引用 8 楼 kndyc 的回复:我是这样做的,然后就抛出了异常。其实就是想要在C++里面调用C#的DoSomething函数

C/C++ code?1234void TestCallBack(void* pf, int value){ pf();}

DoSomething是带有参数的。

而你的函数指针是没有参数的。不异常都不正常。
我声明的DoSomething原型就是不带参数的
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#15 得分:0回复于:
2012-12-08 20:40:28

引用 13 楼 sp1234 的回复:

晕死!低级的系统是个死板的东西,你只能把纯粹静态方法作为参数。
什么纯粹静态呢?把回调函数定义成public static还是一样异常。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
zanfeng
1060151476
等级:


#16 得分:0回复于:
2012-12-08 20:50:04

C/C++ code

?
typedef void (*pfun)(char*); 定义函数指针。

C# code

?
我试了控制台要以输出 Callback called with param
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#17 得分:0回复于:
2012-12-08 22:22:50

引用 16 楼 zanfeng 的回复:

C/C++ code?1234567891011121314// 此类是从 testlib.dll 导出的class TESTLIB_API Ctestlib {public: Ctestlib(void); // TODO: 在此添加您的方法。}; extern TESTLIB_API int ntestlib; TESTLIB_API int fntest……
谢谢,确实可以输出了,但是我在C++当中一直不停的调用回调函数,怎样定义纯粹的静态方法,保证回调函数不被垃圾回收呢?我试了回调函数被调用几次以后就被垃圾回收了。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理




关注
kndyc
kndyc
等级:


#18 得分:0回复于:
2012-12-09 16:03:17

回调函数确实被垃圾回收了,因为定义的位置错了,改过来就好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: