C#调用C++的dll的问题

fyubin 2015-05-07 03:59:10
很奇怪的事情,C#调用C++写好的dll。在两边均已定义好结构体,通过ref进行传值。值可以传出来,但是始终报错:Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

C++端代码如下:
extern "C" _declspec(dllexport) void TestFun(TestStrct *strct);

typedef struct
{
wchar_t *a;
//char* a;
} TestStrct;

void TestFun(TestStrct *strct)
{
strct->a = AnsiToUnicode("asdasd");
//strct->a = "asdasd";
}

C#端代码如下:
[DllImport(@"lib\DiacomTest.dll", CharSet = CharSet.Ansi, EntryPoint = "TestFun", CallingConvention = CallingConvention.Cdecl)]
public static extern void TestFun(ref TestStrct strct);

void iniFun()
{
TestStrct strct = new TestStrct();
strct.a = "111"; //这一步传送进去没有问题
TestFun(ref strct); //这一步永恒报错,但是值可以传出来

Console.WriteLine(strct.a);
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct TestStrct
{
/// WCHAR*
[MarshalAsAttribute(UnmanagedType.LPWStr, SizeConst = 20)]
public string a;
}

在线等,谢谢大侠
...全文
223 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
fyubin 2015-05-11
  • 打赏
  • 举报
回复
引用 5 楼 Saleayas 的回复:
不是所有的 wchar_t * 都可以转换为 string 的。 你这样在非托管内存分配的字符串,需要使用 IntPtr,然后使用 Marshal 获取。并且需要非托管提供释放方法。 如果非托管使用 系统分配的方法,那么是可以使用 String 的。
我觉得我的错误可能就在这里了,IntPtr肯定能获取这边的指针的,但是如果是用ref将结构体作为传递单元的话,确实是报错。我理解应该传结构体指针,然后让结构体指针指向结构体重的某个元素这么去取值,不知道我的想法是不是正确,请您指正。
fyubin 2015-05-11
  • 打赏
  • 举报
回复
引用 3 楼 shingoscar 的回复:
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct TestStrct
{
	//定义错误
	//用
	//public StringBuilder a = new StringBuilder(20);
	//或
	//public char[] a = new char[20];
	[MarshalAsAttribute(UnmanagedType.LPWStr, SizeConst = 20)]
	public string a;
}
我不知道这个方法在您的环境中怎么样,在我这里的话如果用stringbuilder则首先提示不能够使用stringbuilder。char[]是可以的,不过C++那边就太麻烦了,还要组合char数组什么的,特别是需要对每一个通过dll所获得的信息都要重组。
fyubin 2015-05-11
  • 打赏
  • 举报
回复
引用 6 楼 junjun0509 的回复:
酱紫, 1. C++这边TestFunc改成酱:

extern "C" __declspec(dllexport) TestStrct* TestFunc(char* a)   
{  
    TestStrct* strct= (TestStrct*)malloc(sizeof(TestStrct));
    strcpy(strct->a, a); 
    return strct;
}
2.C#这边改成酱:

IntPtr ptr = TestFunc("abcd“);
TestStrct strct= (TestStrct )Marshal.PtrToStructure(ptr, typeof(TestStrct ));
试一下,我没试过,但感觉这样就没问题了
很帅气的想法,不过纠结的地方在于,结构体直接作为返回类型在这样的dll调用中是不被推荐的。这个msdn可以查得到~~谢谢您的回复
QQ萌三国 2015-05-09
  • 打赏
  • 举报
回复
以前遇到过这个异常:也是这样C#调用C++的DLL,网络上找的答案都不合适,最后有人提醒把程序在VS2010上编译、调试,不要在VS2012、VS2013上,然后去试了试,居然就成功了。
Saleayas 2015-05-08
  • 打赏
  • 举报
回复
FreeHGlobal 和 malloc 不对应哦。
被吃了的狗 2015-05-08
  • 打赏
  • 举报
回复
对了,C#这边记得调
Marshal.FreeHGlobal(ptr)
这个~
被吃了的狗 2015-05-08
  • 打赏
  • 举报
回复
酱紫, 1. C++这边TestFunc改成酱:

extern "C" __declspec(dllexport) TestStrct* TestFunc(char* a)   
{  
    TestStrct* strct= (TestStrct*)malloc(sizeof(TestStrct));
    strcpy(strct->a, a); 
    return strct;
}
2.C#这边改成酱:

IntPtr ptr = TestFunc("abcd“);
TestStrct strct= (TestStrct )Marshal.PtrToStructure(ptr, typeof(TestStrct ));
试一下,我没试过,但感觉这样就没问题了
Saleayas 2015-05-08
  • 打赏
  • 举报
回复
不是所有的 wchar_t * 都可以转换为 string 的。 你这样在非托管内存分配的字符串,需要使用 IntPtr,然后使用 Marshal 获取。并且需要非托管提供释放方法。 如果非托管使用 系统分配的方法,那么是可以使用 String 的。
wy24789 2015-05-08
  • 打赏
  • 举报
回复
strct->a = AnsiToUnicode("asdasd"); 这里要copy过去,不能直接赋值,除非全局内存,不知这个函数返回的是什么类型,如果不需要copy,那调用的时候也不用分配空间了
Poopaye 2015-05-07
  • 打赏
  • 举报
回复
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct TestStrct
{
	//定义错误
	//用
	//public StringBuilder a = new StringBuilder(20);
	//或
	//public char[] a = new char[20];
	[MarshalAsAttribute(UnmanagedType.LPWStr, SizeConst = 20)]
	public string a;
}
fyubin 2015-05-07
  • 打赏
  • 举报
回复
引用 1 楼 wy24789 的回复:
strct.a = "111"; //这一步传送进去没有问题 空间小了, strct->a = AnsiToUnicode("asdasd");这有2*6=12字节
C#的结构体中定义的大小为20 strct.a = "111"; 这句只是说我只用了2x3=6字节,我不知道这么理解对不对
wy24789 2015-05-07
  • 打赏
  • 举报
回复
strct.a = "111"; //这一步传送进去没有问题 空间小了, strct->a = AnsiToUnicode("asdasd");这有2*6=12字节

110,533

社区成员

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

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

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