c#调用c++ dll出现“尝试读取或写入受保护的内存”提示

chillystar 2018-07-02 09:04:09
用c++写的一个调用pcl功能的dll,在c++控制台下工作正常,写成dll提供c#调用时,却出现“尝试读取或写入受保护的内存”的提示。分别调整了CallingConvention的参数,结果如下:
CallingConvention.Winapi:尝试读取或写入受保护的内存。
CallingConvention.ThisCall:Debug Assertion Failed!提示窗口。
CallingConvention.StdCall:尝试读取或写入受保护的内存。
CallingConvention.StdCall:无效的非托管调用约定: 必须是 stdcall、cdecl 或 thiscall 之一。
CallingConvention.Cdecl:尝试读取或写入受保护的内存。

代码如下:

[System.Runtime.InteropServices.DllImport(@"D:\新整理\开发\MSC++\PCLLibs\PCLTest\Debug\PCLTest.dll", EntryPoint = "PLYConvert", CallingConvention = CallingConvention.Cdecl)]
public extern static int PLYConvert(string pcdPath, string savePath, float searchRadius, float mu, int nearestNeighbors);

private void Form1_Load(object sender, EventArgs e)
{
PLYConvert(@"D:\新整理\安装与资源\点云数据集\PCDdata\bunny.pcd", @"d:\bunny.ply", 15.0f, 5.0f, 100);
MessageBox.Show("ok");
}

代码是调用PCLTest.dll中的PLYConvert方法,将pcd转为ply。dll的dumpbin查询结果如下:

Dump of file pcltest.dll

File Type: DLL

Section contains the following exports for PCLTest.dll

00000000 characteristics
5B3603A8 time date stamp Fri Jun 29 18:02:16 2018
0.00 version
1 ordinal base
1 number of functions
1 number of names

ordinal hint RVA name

1 0 000444C5 PLYConvert = @ILT+17600(_PLYConvert)

Summary

3000 .data
5000 .idata
18000 .rdata
5000 .reloc
1000 .rsrc
8B000 .text
3F000 .textbss
1000 .tls


请教如何解决该问题?
...全文
1232 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
chillystar 2018-10-30
  • 打赏
  • 举报
回复
很感谢各位大神帮助,其实我是做前端的,搞这pcl实在是赶鸭子上架,虽然最终我水平有限无法解决,但还是很感谢大家热情解答。
小数点666 2018-07-04
  • 打赏
  • 举报
回复
加一个EntryPoint属性,这样应该就没问题了
xian_wwq 2018-07-03
  • 打赏
  • 举报
回复
1.API的定义的有点怪
c是没有string类型的,c++才有
把string改为char*再试试
2.
在dllimport上加上 CharSet声明
如果c dll是多字节,CharSet = CharSet.Ansi
3.
vs支持托管和非托管混合调试
代码都是自己写的,
调试找问题一目了然


xian_wwq 2018-07-02
  • 打赏
  • 举报
回复
把PLYConvert的原型贴出来
P/Invoke调用
凡涉及字符串,就要特别注意 CharSet
c#默认的是Unicode,而c/c++大多都采用多字节
吹风的兔子 2018-07-02
  • 打赏
  • 举报
回复
PInvoke 调用,说白了 就是 封送一段 内存字节。

我们的 int long byte double 字节长度都是固定的。
但是: 数组、字符串 的 字节长度 不固定。

使用 byte[] 自己定义 字节,虽然麻烦,但是也很容易出错,但真心有效 ~
吹风的兔子 2018-07-02
  • 打赏
  • 举报
回复
我似乎有一个 邪典经验:
PInvoke 调用,有一种万能调用方式: 把所有字段 全部改成 byte[]


[System.Runtime.InteropServices.DllImport(@"PCLTest.dll")]
public extern static int PLYConvert(byte[] pcdPath, byte[] savePath, float searchRadius, float mu, int nearestNeighbors);


—— 至于这个 byte[] 该传什么参数,你可以自己尝试。

liulilittle 2018-07-02
  • 打赏
  • 举报
回复
C调用的话,只要不配置默认调用协议 一般是 cdcel 至于字符串这块,你缺少了[MarshalAs]
而且没有指定函数,需求的”执行字符串“的类型(例如:ASCII、Unicode)
不排除C函数DLL本身存在问题,内部发生了一些问题无论是抛出异常,还是设置lastError
都有可能引发”尝试读取或写入受保护的内存“的异常。
chillystar 2018-07-02
  • 打赏
  • 举报
回复
引用 1 楼 xian_wwq 的回复:
把PLYConvert的原型贴出来
P/Invoke调用
凡涉及字符串,就要特别注意 CharSet
c#默认的是Unicode,而c/c++大多都采用多字节


extern "C" __declspec(dllexport) int PLYConvert(string pcdPath, string savePath, float searchRadius, float mu, int nearestNeighbors);

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧