C#调用C++的dll,PInvoke问题和回调函数抛出异常access violation
2016-06-22 16:27
676 查看
不磨叽,直接上代码。
C++动态库中函数定义
在C#中的调用的代码
Audio_OpenChannel方法前的特性标记不能遗漏,特别是EntryPoint和CallingConvention,EntryPoint是C++中头文件定义的方法名,由于C++中是StdCall,所以这里也用StdCall,但是回调函数中的委托要标记为Cdecl,如果委托不标记,那么会抛出异常Access violation。
winform程序调用的代码
这个问题耗了我一天半的时间,这里Mark一下,备忘。
C#调用C++动态库的坑还是很多的。童鞋们注意自身安全!
C++动态库中函数定义
#ifndef _AUDIOSYSSDK_H #define _AUDIOSYSSDK_H typedef void PlayResFunc(void *powner,int filestate, int playlen); extern "C" { int _stdcall Audio_OpenChannel(char *pLocalAddr,PlayResFunc *pFun,void *powner); int _stdcall Audio_CloseChannel(int idx); }
在C#中的调用的代码
#warning 这个委托一定要标记为Cdecl /* 这个委托一定要标记为[System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)], * 否则在C#调用时在回调函数执行一次后会退出或会抛出异常Access violation */ /// Return Type: void ///powner: void* ///filestate: int ///playlen: int [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)] public delegate void PlayResFunc(System.IntPtr powner, int filestate, int playlen);
public class AudioSysSdkHelper { [System.Runtime.InteropServices.DllImportAttribute("AudioSysSDK.dll", EntryPoint = "Audio_OpenChannel", CallingConvention = CallingConvention.StdCall)] public static extern int Audio_OpenChannel(string pLocalAddr,PlayResFunc pFun,System.IntPtr powner); }
Audio_OpenChannel方法前的特性标记不能遗漏,特别是EntryPoint和CallingConvention,EntryPoint是C++中头文件定义的方法名,由于C++中是StdCall,所以这里也用StdCall,但是回调函数中的委托要标记为Cdecl,如果委托不标记,那么会抛出异常Access violation。
winform程序调用的代码
public PlayResFunc PlayResFuncObj = null; private void button3_Audio_OpenChannel_Click(object sender, EventArgs e) { string pLocalAddr = "192.168.7.22"; PlayResFuncObj =PlayRes; channelIndex = AudioSysSdkHelper.Audio_OpenChannel(pLocalAddr, PlayResFuncObj, IntPtr.Zero); if (channelIndex >= 0) { SetTextShow(string.Format("打开通道成功,通道号{0}", channelIndex)); } else { SetTextShow(string.Format("打开通道失败,返回值{0}", channelIndex)); } }
public void PlayRes(IntPtr powner, int filestate, int playlen) { try { int groupid = (int)powner; ePlayStatus state = (ePlayStatus)filestate; switch (state) { case ePlayStatus.PS_PlayDone: SetTextShow("播放完毕"); //System.Diagnostics.Trace.WriteLine("播放完毕"); break; case ePlayStatus.PS_PlayPause: SetTextShow("播放暂停"); //System.Diagnostics.Trace.WriteLine("播放暂停"); break; case ePlayStatus.PS_PlayStatus: SetTextShow(string.Format("播放了百分之{0}", playlen)); //System.Diagnostics.Trace.WriteLine(string.Format("播放了百分之{0}", playlen)); break; } } catch(Exception ex) { throw ex; } }
这个问题耗了我一天半的时间,这里Mark一下,备忘。
C#调用C++动态库的坑还是很多的。童鞋们注意自身安全!
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c#调用COM组件
- FREEBASIC 编译可被python调用的dll函数示例
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- C#实现把指定数据写入串口
- C#动态创建button的方法
- C#中抽象方法与虚拟方法的区别
- c#中虚函数的相关使用方法
- C#实现给图片加水印的方法
- C#使用加边法计算行列式的值
- C#实现多线程的同步方法实例分析
- C#中尾递归的使用、优化及编译器优化
- DLL(Dynamic Linkable Library) 详解说明
- C#中的delegate委托类型基本学习教程
- C#实现子窗体与父窗体通信方法实例总结
- C#通用邮件发送类分享
- 举例讲解C#中自动实现的属性