这是在C++头文件里头的声明extern "C" __declspec(dllexport) char* __stdcall getb(char * str);这是函数的定义char * __stdcall getb(char * str)
{
string strb(str);
char * xstr = (char *)strb.c_str();
return xstr;
}这是C#里头函数导入的代码 public class Utility
{
[DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr getb(IntPtr inp);
}这里是C#里调用函数的代码 string str = "AAAA";
IntPtr trb = Utility.getb(Marshal.StringToBSTR(str));
string b = Marshal.PtrToStringBSTR(trb);觉得好奇怪,怎么调用函数的时候会提示异常:
未处理AccessViolationException
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
而且如果把函数定义改成直接返回参数的指针,就没有问题:char * __stdcall getb(char * str)
{
return str;
}感觉应该是string里头出问题了吧~但是不知道错哪了,怎么修改,而且开始的想法不是只把char*放到string里头再得到char*,中间还有对那个string进行操作的。
请高手们帮忙找找错误~谢谢了~~
{
string strb(str);
char * xstr = (char *)strb.c_str();
return xstr;
}这是C#里头函数导入的代码 public class Utility
{
[DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr getb(IntPtr inp);
}这里是C#里调用函数的代码 string str = "AAAA";
IntPtr trb = Utility.getb(Marshal.StringToBSTR(str));
string b = Marshal.PtrToStringBSTR(trb);觉得好奇怪,怎么调用函数的时候会提示异常:
未处理AccessViolationException
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
而且如果把函数定义改成直接返回参数的指针,就没有问题:char * __stdcall getb(char * str)
{
return str;
}感觉应该是string里头出问题了吧~但是不知道错哪了,怎么修改,而且开始的想法不是只把char*放到string里头再得到char*,中间还有对那个string进行操作的。
请高手们帮忙找找错误~谢谢了~~
解决方案 »
- sos...关于c#...
- 如何将文字、图片、表格保存到数据库中?
- WPF 菜单淡化效果
- .NET和c#之间有什么关系?
- 如何访问一个页面上的图片?页面图片(验证码)是一个x.asp?r=随机数,的形式
- Excel Quicker 1.4A正式发布 ,欢迎大家下载、跟贴
- 谁给个MSNP9的协议我看看?要详细点的,最好是中文的,在线等
- WinForm如何实现这种效果?
- 只调空的内容进入内存的SQL语句
- 在属性前面加virtual是什么意思?(C#)
- devexpress TreeList 如何设置这个ParentFieldName?(内有数据说明)
- [50]如何点击关闭windowsform的时候确认是否关闭,弱是才关闭?
改成:strcpy(xstr,strb.c_str());试试。
CallingConvention.StdCall调用
不对的,应该对应起来。
char * __stdcall getb(char * str)
{
string strb(str);
char * xstr = (char *)strb.c_str();
return xstr;
}
这样写有问题。
string strb(str);
strb创建在栈中,return xstr导致了strb的析构,strb中创建的字符串也随之丢失。
xstr指向strb创建的字符串,后果就是xstr指向已经释放的内存。
[DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern string getb(string str);另LZ的C++写法不对,如可以返回std::string类型,不能返回指向函数内部临时变量的指针,这是危险的。
extern "C" __declspec(dllexport) int __stdcall getb(char * str,char* out);
这样定义,使用out来返回字符串。
是你的C++DLL有问题,问题不出在平台调用这里。
这个DLL本身设计的不够严密,才出现的错误。
继续请教各位大大
用输出参数返回临时变量的指针是可以的吗?
需不需要new?
但是new了以后在什么地方释放呢?还要另外导出一个释放空间的方法让C#调用吗?
要不我也一个dll你调用一下?
extern "C" __declspec(dllexport) char* __stdcall getb(char * str);
假设这里str是作输出参数用,那么定义成:
[DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern string getb(StringBuilder sb); StringBuilder sb = new StringBuilder(256);//由C#申请空间。
getb(sb);//C++里注意内存不要越界。
C++的函数改成了如下:
int __stdcall getb(char* str,char* out)
{
string strb(str);
int len = strb.length();
out = new char[len + 1];
strcpy(out,strb.c_str());
return 1;
}
extern "C" __declspec(dllexport) int __stdcall getb(char * str,char * out);
导出 [DllImport("bb.dll", EntryPoint = "_getb@8", CallingConvention = CallingConvention.StdCall)]
public static extern int getb(IntPtr inp,out IntPtr outp);
调用 string str = "AAAA";
IntPtr outp;
Utility.getb(Marshal.StringToBSTR(str),out outp);
string b = Marshal.PtrToStringBSTR(outp);怎么调用了getb之后,outp是0???
还是不行额。。C#里代码修改后如下: [DllImport("bb.dll", EntryPoint = "_getb@8", CallingConvention = CallingConvention.StdCall)]
public static extern int getb(string str, StringBuilder strout); StringBuilder sb = new StringBuilder(100);
Utility.getb(str, sb);调用完getb以后sb里头没东西。。
抓狂ing。。
{
string strb(str);
int len = strb.length();
out = new char[len + 1];
strcpy(out,strb.c_str());
return 1;
}
extern "C" __declspec(dllexport) int __stdcall getb(char * str,char * out);
{
string strbbb(str);
int len = strbbb.length();
char* out = new char[len + 1];
strcpy(out,strbbb.c_str());
return out;
}
string str = "AAAA";
IntPtr ptrout = Utility.getbbb(Marshal.StringToBSTR(str)); string sb = Marshal.PtrToStringBSTR(ptrout);这样的话是“未处理OutOfMemoryException”
引发类型为“System.OutOfMemoryException”的异常。
排错提示:
如果要创建数组,请确保大小正确
对于内部用途和新的托管对象,确保有足够的内存可供分配。。
如果这样: [DllImport("bb.dll", EntryPoint = "_getbbbb@4", CallingConvention = CallingConvention.StdCall)]
public static extern StringBuilder getbbb(IntPtr inp); string str = "AAAA";
StringBuilder sb = new StringBuilder(100);
sb = Utility.getbbb(Marshal.StringToBSTR(str));StringBulider里头就只有一个A (- -!)
[DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern StringBuilder getb(string str);
StringBuilder sb = new StringBuilder(100);
sb = Utility.getbbb(str);就是还是搞不明白为什么输出参数用不了呢?
还有Marshell类的那些转换函数到底用在什么场合呢?string就可以自动转换成char *,返回的时候用StringBuilder也可以自己转换
哎。。这阵子太痛苦了,写程序不是这样的问题,就是那样的问题,都搞我个半天,都快没激情了。。
那是调用方法不正确,改下如下:
string str = "AAAA";
IntPtr ptr= Marshal.StringToCoTaskMemAnsi(str);
int n= getb(ptr);
string ss = Marshal.PtrToStringAnsi(ptr);
Marshal.FreeCoTaskMem(ptr);
int __stdcall getb(char* str,char* out)
{
string strb(str);
int len = strb.length();
//out = new char[len + 1];//去掉这一行
strcpy(out,strb.c_str());
return 1;
}C#调用方法
[DllImport("bb.dll", EntryPoint = "_getb@8", CallingConvention = CallingConvention.StdCall)]
public static extern int getb(string str, StringBuilder strout);
StringBuilder sb = new StringBuilder(100);
Utility.getb(str, sb);
这种方法不对,虽然你拿到正确的值,但这是偶然. [DllImport("bb.dll", EntryPoint = "_getb@4", CallingConvention = CallingConvention.StdCall)]
public static extern StringBuilder getb(string str);
感觉Marshal类里头好多函数很像啊~去msdn里头查下区别先~
什么样的字符串是ANSI的?又有什么样的是BSTR的呢?还有ASCII。。
还有这个PtrToStringAuto 已重载。 分配托管 String,并从非托管字符串向其复制指定数目的字符。是什么时候用的呢?