700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > C# DllImport DLL非托管动态链接库 问题总结

C# DllImport DLL非托管动态链接库 问题总结

时间:2021-06-26 07:47:33

相关推荐

C# DllImport DLL非托管动态链接库 问题总结

C#程序实现动态调用DLL的研究(转载) - 黄金海岸 - 博客园 ()/goldenocean/archive//09/20/509558.html

C# 调用c++ dll 尝试读取或写入受保护的内存 错误-CSDN社区/topics/340067302步骤:

1,确定是托管动态链接库还是非托管动态链接库;

2,如为C++ 等非托管动态链接库:首先确定 C++ DLL的导出类型是否是_stdcall,默认的是_cdcel,具体枚举值含义如下图所示:

/// <summary>/// 初始化视频解码库/// </summary>/// <param name="num">通道数 7</param>/// <param name="portList">监听端口列表,端口号必须是偶数。通道数目和端口数目匹配。例:int[] {8000,8002,...}</param>/// <param name="buffSize">每个通道的队列大小 10.</param>/// <param name="w">图像的宽</param>/// <param name="h">图像的高</param>/// <param name="callback">注册C#函数接口到DLL里面。可以为null</param>/// <param name="ip">视频转发的目的ip</param>/// <param name="dir">当前程序路径,方便同步</param>/// <param name="rec_file_path">视频文件记录路径</param>/// <returns></returns>[DllImport(LIBUSB_DLL, SetLastError = true, CallingConvention = CallingConvention.StdCall, EntryPoint = "setup_channal")]internal static extern int setup_channal(uint num, int portList, int buffSize, int w, int h, [MarshalAs(UnmanagedType.FunctionPtr)] CallbackDelegate callback, IntPtr ip , IntPtr dir, IntPtr rec_file_path);

首先,应该在C#语言源程序中声明外部方法,其基本形式是:

[DLLImport(“DLL文件”)]

修饰符extern返回变量类型方法名称(参数列表)

其中

DLL文件:包含定义外部方法的库文件。

修饰符:访问修饰符,除了abstract以外在声明方法时可以使用的修饰符。

返回变量类型:在DLL文件中你需调用方法的返回变量类型。

方法名称:在DLL文件中你需调用方法的名称。

参数列表:在DLL文件中你需调用方法的列表。

注意:需要在程序声明中使用System.Runtime.InteropServices命名空间。

DllImport只能放置在方法声明上。

DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。

返回变量类型、方法名称、参数列表一定要与DLL文件中的定义相一致。

若要使用其它函数名,可以使用EntryPoint属性设置,如:

[DllImport("user32.dll", EntryPoint="MessageBoxA")]

static extern int MsgBox(int hWnd, string msg, string caption, int type);

其它可选的DllImportAttribute属性:

CharSet指示用在入口点中的字符集,如:CharSet=CharSet.Ansi;

SetLastError指示方法是否保留Win32"上一错误",如:SetLastError=true;

ExactSpelling指示EntryPoint是否必须与指示的入口点的拼写完全匹配,如:ExactSpelling=false;

PreserveSig指示方法的签名应当被保留还是被转换,如:PreserveSig=true;

CallingConvention指示入口点的调用约定,如:CallingConvention=CallingConvention.Winapi;

如上图 存在为个回调函数的参数

/// <summary>/// 注册给C++的委托(函数指针)/// </summary>/// <param name="array"></param>/// <param name="size"></param>// 不使用如下修饰,会导致C#在调用完后,释放pData内容,导致C程序崩溃;所以在声明代理的时候,说明是C回调,不会收里面资源 [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)]public delegate void CallbackDelegate(IntPtr array, IntPtr ImgPtr, int size);

1,遇到问题:有时则能运行起来,但会抛出异常:

System.AccessViolationException:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

解决办法:声明UnmanagedFunctionPointerAttribute属性时 默认是CallingConvention.StdCall,需要确定 C++ DLL的导出类型是否是_stdcall,默认的是_cdcel

2,参数转换 C++ --> C# 详细浏览下面链接:

internal const string LIBUSB_DLL = @"avideo_libs\avideo_helper.dll";

internal const string DIR_PATH = @"./avideo_libs/";

internal const string REC_FILE_PATH = @"./RecFiles/";

video_helper.setup_channal(ch, port, 1, width, height, callback[0], Marshal.StringToHGlobalAnsi(turnIP),

Marshal.StringToHGlobalAnsi(DIR_PATH), Marshal.StringToHGlobalAnsi(REC_FILE_PATH));//同时转发给

最详细的C++对应C#的数据类型转换 - Innershar - 博客园 ()/innershare/p/10594775.html回调函数

/// <summary>/// 解码库被调用接口/// </summary>/// <param name="ImgStructPtr">图像数据结构体</param>/// <param name="ImgPtr">当前图像的起始指针</param>/// <param name="size">当前图像的总字节数</param>[HandleProcessCorruptedStateExceptions]private void CallBackFunction(IntPtr ImgStructPtr, IntPtr ImgPtr, int size){try{if (ImgPtr == IntPtr.Zero || size <= 0){return;}if (video_helper.Isreleased){return;}time_start = timeGetTime();//if (imageTypeDef.img_ptr == 0)//{// imageTypeDef = Marshal.PtrToStructure<ImageTypeDef>(ImgStructPtr);//}/// bitma初始化放在工作线程中,避免跨线程操作if (bitmap == null){bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, (IntPtr)ImgPtr);//bytes = new byte[width * height * 4];//rect = new Rectangle(this.Location.X, this.Location.Y, width, height);}//BitmapData bData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);//if (ImgPtr != bData.Scan0)//{// bData.Scan0 = ImgPtr;//}//bitmap.UnlockBits(bData);this.BeginInvoke(new Action(() =>{try{this.label_nosignal.Visible = false;if (this.CameraPictureBox.InvokeRequired){Action action = new Action(() => { this.CameraPictureBox.Image = bitmap; });this.BeginInvoke(action);}else{this.CameraPictureBox.Image = bitmap;}if (this.label_nosignal.Visible == true)this.label_nosignal.Visible = false;}catch (Exception ex){MessageBox.Show(ex.Message, "PictureBo渲染失败失败", MessageBoxButtons.OK, MessageBoxIcon.Error);}}));}catch (Exception ex){MessageBox.Show(ex.Message, "解码库接口Bitmap初始化失败", MessageBoxButtons.OK, MessageBoxIcon.Error);}return;}

添加HandleProcessCorruptedStateExceptions 属性 可以捕获AccessViolationException类型错误:详细操作见 如下链接:

.NET 4.0 调用 C dll 触发 AccessViolationException 异常的处理方案_于大大大洋的博客-CSDN博客/arrowzz/article/details/80898718

回调 ImgPtr 参数为当前图像的起始指针, 如果初始化bitmap 在this.BeginInvoke(new Action(() =>{

bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, (IntPtr)ImgPtr);

});

中,会抛出异常:

System.AccessViolationException:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

捕获System.AccessViolationException异常后,会报错:对象当前正在其他地方使用。涉及到C++指针跨线程操作;

解决方法:bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, (IntPtr)ImgPtr);放在回调工作线程中初始化。

(1条消息) C# 中intptr用法_Arno0377的博客-CSDN博客_c# intptr详解/qq_39008744/article/details/106868106?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&utm_relevant_index=2

(1条消息) C++多线程与共享指针_宁静深远的博客-CSDN博客_共享指针 线程安全/u012477435/article/details/106875121

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。