C# 调用C++ DLL提示“尝试读取或写入受保护的内存。”

zengwenjian 2014-03-20 05:30:59
我要用C#调用C++的DLL(里面是关于DES加密的算法),但是调用是有时会报错提示“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”
C#调用的代码:
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern string desEncrypt2(string keyText, string plainText);

C++代码:
char *desEncrypt2(char *encryptedText, const char *plainText)
{
unsigned char buf[9];
char hex[17];

unsigned char longbuf[512+1];
char longhex[512*2+1];

memset(buf, 0, sizeof(buf));
memset(hex, 0, sizeof(hex));
memset(longbuf, 0, sizeof(longbuf));
memset(longhex, 0, sizeof(longhex));

strncpy((char *)longbuf, plainText, sizeof(longbuf)-1); //平台移植到2008的需要,strncpy->strncpy_s
int index;
for (index = 0; longbuf[index]; index += 8)
{
memcpy(buf, longbuf+index, 8);
DesEncrypt(key, buf);
for (int i=0; i < 8; i++)
sprintf(hex+2*i, "%02x", buf[i]);
memcpy(longhex+2*index, hex, 16);
}

strcpy(encryptedText, longhex);

return encryptedText;
}
很可能是strcpy(encryptedText, longhex);这句导致的,但是去掉直接返回longhex又是乱码。
我在网上找了很久,有说分配的内存空间没有释放,请问“unsigned char longbuf[512+1];char longhex[512*2+1];”,这两个要释放的吗?不是动态分配啊,我不大懂C++麻烦各位帮忙了。
另外,我用的是VS2010的平台
...全文
385 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
zengwenjian 2014-03-26
  • 打赏
  • 举报
回复
谢谢,各位大神了,按上面说的两种意见改好之后,用了两天都没问题应该是OK.。 总结一下可行的方案,给以后遇到这问题的兄弟: 1.用IntPtr指针接收返回值和传送参数的方式; 2.17楼大神的:返回值是string 如果是参数的就要用StringBuider。
bigbaldy 2014-03-24
  • 打赏
  • 举报
回复
返回值必须是IntPtr类型,然后用下面代码取值

Marshal.PtrToStringAnsi(desEncrypt2("xxx","xxx"));
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
大概是哪里的参数类型不对啊? 我这段时间还试过把返回的string 换成StringBuilder还是有问题 C#调用的代码: [DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern StringBuilder desEncrypt2(string keyText, string plainText);
lfqsy 2014-03-24
  • 打赏
  • 举报
回复
参数类型不对??
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
各位大侠赶紧出来救命啊
Yun__ 2014-03-24
  • 打赏
  • 举报
回复
这个提示貌似是指针的问题...貌似有个函数可以把string转成IntPtr 然后传到c++ 然后把c++把字符串传出来 成为IntPtr再c#转成string
bigbaldy 2014-03-24
  • 打赏
  • 举报
回复
输入不变char*类型用string,可变的用stringbuilder,返回char*一律用IntPtr,或者你直接用byte*接收返回值,毕竟你返回的是加密串,有一点楼主别忘了,C#是支持指针的,用指针方便得多
bigbaldy 2014-03-24
  • 打赏
  • 举报
回复
引用 12 楼 zengwenjian 的回复:
调用DLL部分: [DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern StringBuilder desEncrypt2(string keyText, string plainText); 实际调用时: Marshal.PtrToStringAnsi(LowDes.desEncrypt2(key, pass)); 但是报错: 错误 1 与“System.Runtime.InteropServices.Marshal.PtrToStringAnsi(System.IntPtr)”最匹配的重载方法具有一些无效参 错误 2 参数 1: 无法从“System.Text.StringBuilder”转换为“System.IntPtr”
你得把你的函数声明中的返回值改为IntPtr呀
本拉灯 2014-03-24
  • 打赏
  • 举报
回复
引用 20 楼 zengwenjian 的回复:
[quote=引用 17 楼 wyd1520 的回复:] [DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern string desEncrypt2(string keyText, StringBuider plainText);<-要这样 返回值是string 如果是参数的就要用StringBuider
这个方法也是可以的,我记得我看过一篇帖子是说返回值用StringBuider,参数用string ,我就那样改了,但是第一运行可以后面只有重新编译才不会报内存错误。看来是我之前理解错了,谢谢了。[/quote] 你理解错了。如果是返回值一般是string 如果是 参数是为指针并且在方法内部有改动这个指针指向的值,那是要用StringBuider 如果没有用string也可以
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
引用 17 楼 wyd1520 的回复:
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern string desEncrypt2(string keyText, StringBuider plainText);<-要这样 返回值是string 如果是参数的就要用StringBuider
这个方法也是可以的,我记得我看过一篇帖子是说返回值用StringBuider,参数用string ,我就那样改了,但是第一运行可以后面只有重新编译才不会报内存错误。看来是我之前理解错了,谢谢了。
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
我用下面这个函数给IntPtr 赋值的,我估计是这里面出了问题。 private static IntPtr mallocIntptr( string strData ) { //先将字符串转化成字节方式 Byte[] btData = System.Text.Encoding.Default.GetBytes(strData); //申请非拖管空间 IntPtr m_ptr = Marshal.AllocHGlobal(btData.Length); //给非拖管空间清0 Byte[] btZero = new Byte[btData .Length+ 1]; //一定要加1,否则后面是乱码,原因未找到 Marshal.Copy(btZero, 0, m_ptr, btZero.Length); //给指针指向的空间赋值 Marshal.Copy(btData, 0, m_ptr, btData.Length); return m_ptr; }
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
引用 15 楼 u012948520 的回复:
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern string desEncrypt2(IntPtr keyText, IntPtr plainText); IntPtr keyText = Marshal.AllocHGlobal(2000); IntPtr plainText = Marshal.AllocHGlobal(2000); IntPtr result = Marshal.AllocHGlobal(2000); 用函数的时候就 result = desEncrypt2(keyText, plainText); 试试看
这种方法是有效的,但是会引起一个新的问题"vshost32.exe已停止工作"。 问题签名: 问题事件名称: APPCRASH 应用程序名: TelSystem.vshost.exe 应用程序版本: 10.0.30319.1 应用程序时间戳: 4ba2084b 故障模块名称: ntdll.dll 故障模块版本: 6.1.7601.18247 故障模块时间戳: 521ea8e7 异常代码: c0000005 异常偏移: 0002e41b OS 版本: 6.1.7601.2.1.0.256.1 区域设置 ID: 2052 其他信息 1: ba42 其他信息 2: ba4221b18d4772df025e6cf90b5164dd 其他信息 3: fd90 其他信息 4: fd90b03f4a21daf98269c88165305185
本拉灯 2014-03-24
  • 打赏
  • 举报
回复
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern string desEncrypt2(string keyText, StringBuider plainText);<-要这样 返回值是string 如果是参数的就要用StringBuider
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
引用 13 楼 wyd1520 的回复:
CONST CHAR* 对应的C#类型 是 StringBuilder 用这个试试
我刚才试了一下 DLL部分只是把函数改为 const char *desEncrypt2(char *encryptedText, const char *plainText); 就是增加了const 调用DLL部分还是原来那样: [DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern StringBuilder desEncrypt2(string keyText, string plainText); 但是还是提示“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”
白衣如花 2014-03-24
  • 打赏
  • 举报
回复
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern string desEncrypt2(IntPtr keyText, IntPtr plainText); IntPtr keyText = Marshal.AllocHGlobal(2000); IntPtr plainText = Marshal.AllocHGlobal(2000); IntPtr result = Marshal.AllocHGlobal(2000); 用函数的时候就 result = desEncrypt2(keyText, plainText); 试试看
白衣如花 2014-03-24
  • 打赏
  • 举报
回复
IntPtr对应指针类型 19位的char * 对应20位的char[]
本拉灯 2014-03-24
  • 打赏
  • 举报
回复
CONST CHAR* 对应的C#类型 是 StringBuilder 用这个试试
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
调用DLL部分: [DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern StringBuilder desEncrypt2(string keyText, string plainText); 实际调用时: Marshal.PtrToStringAnsi(LowDes.desEncrypt2(key, pass)); 但是报错: 错误 1 与“System.Runtime.InteropServices.Marshal.PtrToStringAnsi(System.IntPtr)”最匹配的重载方法具有一些无效参 错误 2 参数 1: 无法从“System.Text.StringBuilder”转换为“System.IntPtr”
bigbaldy 2014-03-24
  • 打赏
  • 举报
回复
引用 10 楼 zengwenjian 的回复:
IntPtr类型算是整形吧,我在C++里面要返回的是一个字串类型是char * 的,需要用怎么转换吗?
你把intptr理解成指针就行了,转换就用我上面的方法呀
zengwenjian 2014-03-24
  • 打赏
  • 举报
回复
引用 9 楼 bigbaldy 的回复:
返回值必须是IntPtr类型,然后用下面代码取值

Marshal.PtrToStringAnsi(desEncrypt2("xxx","xxx"));
IntPtr类型算是整形吧,我在C++里面要返回的是一个字串类型是char * 的,需要用怎么转换吗?
加载更多回复(5)

110,538

社区成员

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

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

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