.net调用非托管dll,debug和release版本结果不同!
vc++的dll函数原型如下,有三个:extern "C" _declspec(dllexport)
int solution
(char* roverfile,int iRoverModel,
TOutputPt** vRes,
bool bStatic=true);
//设置基准站信息
extern "C" _declspec(dllexport)
void SetBaseInfo(
char * strBaseFile,/*基准站绝对路径*/
double B,
double L,
double H /*基准站BLH坐标*/
);
extern "C" _declspec(dllexport)
void DestroyOutputPt (TOutputPt** vRes);
我在.net里面调用改成了这样的:
[DllImport("USolution.dll")] // dll在磁盘中的存放位置
public static extern int solution(string roverfile, int iRoverModel, ref IntPtr vRes, bool bStatic);
[DllImport("USolution.dll")] // dll在磁盘中的存放位置
//[DllImport(@"F:\“调查之星”后差分相关资料和说明\“调查之星”后差分相关资料和说明\USolution\Release\USolution.dll")] // dll在磁盘中的存放位置
public static extern void SetBaseInfo(string strBaseFile,double B,double L,double H);
[DllImport("USolution.dll")]
public static extern void DestroyOutputPt(IntPtr vRes);
调用部分(主要是solution这个函数)
//解算
int iEpoches = -1;
IntPtr vRes = new IntPtr(Marshal.SizeOf(typeof(TOutputPt)));
iEpoches = solution(roverfile, 0, ref vRes, true);
if (iEpoches >= 0)
{
//解算成功,将解算结果写入输出文件
TOutputPt[] pts = new TOutputPt[iEpoches];
IntPtr pt = vRes;
for (int i = 0; i < iEpoches; i++)
{
pts[i] = (TOutputPt)Marshal.PtrToStructure(pt, typeof(TOutputPt));
pt = (IntPtr)((int)pt + Marshal.SizeOf(typeof(TOutputPt)));
}
InputToFile(pts,outfile);
DestroyOutputPt(vRes);
运行结果:
在debug下面是对的,iEpoches 为一个正数,TOutputPt的vRes也有值
但是在release下面,iEpoches为一个负数,这个负数在dll里面表示说“内存不足”
这个错误搞了两天了,试了很多方法,但是仍然没有找到解决办法,望各位高手不宁赐教啊~小女子感激不尽!! --------------------编程问答-------------------- 注明:
TOutputPt是结构体
public struct TOutputPt
{
public double dGpsTime; //gps时间
public double B;
public double L;
public double H;
public double Fit; //越接近 0 代表解算精度越高
} --------------------编程问答-------------------- 太复杂了,看不懂。 --------------------编程问答-------------------- 在函数调用过程中,所有调用信息(返回地址、参数)以及自动变量都是放在栈中的。若函数的声明与实现不同(参数、返回值、调用方式),就会产生错误————但 Debug 方式下,栈的访问通过 EBP 寄存器保存的地址实现,如果没有发生数组越界之类的错误(或是越界“不多”),函数通常能正常执行;Release 方式下,优化会省略 EBP 栈基址指针,这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。C++ 的强类型特性能检查出大多数这样的错误,但如果用了强制类型转换,就不行了。你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略,以确定是否此类错误。
详细说明请访问http://hi.baidu.com/%D6%D9%C1%C1%C1%C1/blog/item/b3087b2591051e6635a80f55.html
--------------------编程问答-------------------- 楼上的强.受教了 --------------------编程问答-------------------- 晓习 顶顶更健康 --------------------编程问答-------------------- 我是来凑热闹的 --------------------编程问答-------------------- bbb16517:
你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略,以确定是否此类错误。
这个设置在vs.net哪里啊 没找到。。。
--------------------编程问答-------------------- TOutputPt加上#pragma pack(1) --------------------编程问答-------------------- 是不是调用约定的问题,你把C++中的函数原型改成如下试试:
extern "C" _declspec(dllexport)int __stdcall solution(char* roverfile,int iRoverModel, TOutputPt** vRes, bool bStatic=true);
或者C#中的定义改成:
[DllImport("USolution.dll", CallingConvention = CallingConvention.Cdecl)] // dll在磁盘中的存放位置--------------------编程问答-------------------- 在 Project\Settings... 中可以设置/Oy- 编译选项。
public static extern int solution(string roverfile, int iRoverModel, ref IntPtr vRes, bool bStatic);
你也可以像 Debug 一样调试你的 Release 版,只要加入调试符号。在 Project/Settings... 中,选中 Settings for "Win32 Release",选中 C/C++ 标签,Category 选 General,Debug Info 选 Program Database。再在 Link 标签 Project options 最后加上 "/OPT:REF" (引号不要输)。这样调试器就能使用 pdb 文件中的调试符号。但调试时你会发现断点很难设置,变量也很难找到——这些都被优化过了。
具体请查看:http://www.builder.com.cn/2008/0706/964938.shtml --------------------编程问答-------------------- zhangxuyu1118:
加那个是什么意思啊?
dk385:
照你的说的改了,但是还是不行
--------------------编程问答-------------------- 把有关的C++代码也贴上来。 --------------------编程问答-------------------- dk385:
dll我没有源码
只有一个vc++使用dll做的一个示例代码
extern "C" _declspec(dllexport)
int solution
(char* roverfile,int iRoverModel,
TOutputPt** vRes,
bool bStatic=true);
//设置基准站信息
extern "C" _declspec(dllexport)
void SetBaseInfo(
char * strBaseFile,/*基准站绝对路径*/
double B,
double L,
double H /*基准站BLH坐标*/
);
extern "C" _declspec(dllexport)
void DestroyOutputPt (TOutputPt** vRes);
我是要用C#调用这个dll做
不晓得你要看的是不是这个? --------------------编程问答-------------------- up up up
高手快来啊~ --------------------编程问答-------------------- 单是这样很难判断问题出在那,
你说在debug下面是对的,iEpoches 为一个正数,TOutputPt的vRes也有值
是不是说调用没有问题,而且这里的代码调用完全正确?
int iEpoches = -1;
IntPtr vRes = new IntPtr(Marshal.SizeOf(typeof(TOutputPt)));
iEpoches = solution(roverfile, 0, ref vRes, true);
if (iEpoches >= 0)
{
//解算成功,将解算结果写入输出文件
TOutputPt[] pts = new TOutputPt[iEpoches];
IntPtr pt = vRes;
for (int i = 0; i < iEpoches; i++)
{
pts[i] = (TOutputPt)Marshal.PtrToStructure(pt, typeof(TOutputPt));//这里也能取到正确的值?
pt = (IntPtr)((int)pt + Marshal.SizeOf(typeof(TOutputPt)));
}
InputToFile(pts,outfile);
DestroyOutputPt(vRes);
但是在release下面,iEpoches为一个负数,这个负数在dll里面表示说“内存不足”.
从你的代码看,dll里是申请了内存然后地址赋给传入的vRes变量的。 这步出错? 对比下你的C#项目中debug版本和Release版设置有什么不同?
最好让DLL的开发者协助下,帮助解决问题。 --------------------编程问答-------------------- 冲星,帮顶,接分! --------------------编程问答-------------------- 顶!
补充:.NET技术 , C#