当前位置:编程学习 > C#/ASP.NET >>

.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在磁盘中的存放位置
public static extern int solution(string roverfile, int iRoverModel, ref IntPtr vRes, bool bStatic);
--------------------编程问答-------------------- 在 Project\Settings... 中可以设置/Oy- 编译选项。
你也可以像 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#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,