求助:在C#中如何调用Dephi写的接口函数(内含结构体及结构体指针)

时间:2022-08-30 19:13:27
==================================================================================
接口中的数据结构定义

  //查询卡返写区结构
  Type
    TCheckReturn = Record
      str_Mark:       String[2];  //返写标志
      e_Left:         Double;     //剩余电量
      e_SumBuy:       Double;     //累计购电量
      e_Overall:      Double;     //当前总累计用电量
      e_Tine:         Double;     //当前尖累计用电量
      e_Apex:         Double;     //当前峰累计用电量
      e_Calm:         Double;     //当前平累计用电量
      e_Vale:         Double;     //当前谷累计用电量
      e_reverse:      Double;     //反向电量
      str_State:      String[2];  //水表工作状态字
      str_MeterNo:    String[12]; //电表表号
      str_Date:       String[6];  //当前日期
      e_Freeze3:      Double;     //冻结电量3
      e_Freeze2:      Double;     //冻结电量2
      e_Freeze1:      Double;     //冻结电量1
      str_FreezeTime: String[2];  //电量冻结日
      str_UserNo:     String[12]; //用户号
      i_Times:        Integer;    //购电次数
      e_Alarm1:       Double;     //报警电量1
      e_Alarm2:       Double;     //报警电量2
      e_OverValue:    Double;     //透支电量限额
      e_InputValue:   Double;     //囤积电量限额
    End;
    PCheckReturn = ^TCheckReturn;

  //根密钥
  Type
    TRootKey = Record
      str_MainKey:        String[32]; //电表主控密钥
      str_InsideKey:      String[32]; //系统内部认证密钥
      str_MeterReturnKey: String[32]; //电表反馈外部认证主密钥
      str_EleInfoKey:     String[32]; //电量外部认证密钥
      str_EleReturnKey:   String[32]; //电表返写数据加密密钥
      str_DecryptKey:     String[32]; //电表购电数据解密密钥
      str_BuyEleKey:      String[32]; //电表购电外部认证密钥
    End;

以下是接口中的函数原型:
  //发检查卡
  Function MadeCheck(CommHandle: THandle; TRK: TRootKey; Var i_Error: Integer):
                     Boolean; StdCall; External 'EleMeter.DLL';
  //读检查卡
  Function ReadCheck(CommHandle: THandle; CheckReturn: PCheckReturn; Var i_Error:
                     Integer): Boolean; StdCall; External 'EleMeter.DLL';
==========================================================================
在C#中的代码:
结构定义:
    //查询卡返写区结构
    [StructLayout(LayoutKind.Sequential)]
    public struct CheckReturn
    {
        //Type
        //  TCheckReturn = Record
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] strMark;//    str_Mark:       String[2];  //返写标志
        public double dLeft; //    e_Left:         Double;     //剩余电量
        public double dSumBuy; //    e_SumBuy:       Double;     //累计购电量
        public double dOverall; //    e_Overall:      Double;     //当前总累计用电量
        public double dTine; //    e_Tine:         Double;     //当前尖累计用电量
        public double dApex; //    e_Apex:         Double;     //当前峰累计用电量
        public double dCalm; //    e_Calm:         Double;     //当前平累计用电量
        public double dVale; //    e_Vale:         Double;     //当前谷累计用电量
        public double dReverse; //    e_reverse:      Double;     //反向电量
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] strState; //    str_State:      String[2];  //水表工作状态字
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public char[] strMeterNo; //    str_MeterNo:    String[12]; //电表表号
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public char[] strDate; //    str_Date:       String[6];  //当前日期
        public double dFreeze3; //    e_Freeze3:      Double;     //冻结电量3
        public double dFreeze2; //    e_Freeze2:      Double;     //冻结电量2
        public double dFreeze1; //    e_Freeze1:      Double;     //冻结电量1
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] strFreezeTime; //    str_FreezeTime: String[2];  //电量冻结日
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public char[] strUserNo; //    str_UserNo:     String[12]; //用户号
        public int iTimes; //    i_Times:        Integer;    //购电次数
        public double dAlarm1; //    e_Alarm1:       Double;     //报警电量1
        public double dAlarm2; //    e_Alarm2:       Double;     //报警电量2
        public double dOverValue; //    e_OverValue:    Double;     //透支电量限额
        public double dInputValue; //    e_InputValue:   Double;     //囤积电量限额
        //  End;
        //  PCheckReturn = ^TCheckReturn;
        public void init()
        {
            strMark = "99".ToCharArray();
            dLeft = 9.9;
            dSumBuy = 9.9;
            dOverall = 9.9;
            dTine = 9.9;
            dApex = 9.9;
            dCalm = 9.9;
            dVale = 9.9;
            dReverse = 9.9;
            strState = "99".ToCharArray();
            strMeterNo = "999999999999".ToCharArray();
            strDate = "999999".ToCharArray();
            dFreeze3 = 9.9;
            dFreeze2 = 9.9;
            dFreeze1 = 9.9;
            strFreezeTime = "99".ToCharArray();
            strUserNo = "999999999999".ToCharArray();
            iTimes = 9;
            dAlarm1 = 9.9;
            dAlarm2 = 9.9;
            dOverValue = 9.9;
            dInputValue = 9.9;
        }
    }
    //根密钥文件结构
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct RootKey
    {
        //Type
        //  TRootKey = Record
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strMainKey; //    str_MainKey:        String[32]; //电表主控密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strInsideKey; //    str_InsideKey:      String[32]; //系统内部认证密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strMeterReturnKey; //    str_MeterReturnKey: String[32]; //电表反馈外部认证主密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strEleInfoKey; //    str_EleInfoKey:     String[32]; //电量外部认证密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strEleReturnKey; //    str_EleReturnKey:   String[32]; //电表返写数据加密密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strDecryptKey; //    str_DecryptKey:     String[32]; //电表购电数据解密密钥
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] strBuyEleKey; //    str_BuyEleKey:      String[32]; //电表购电外部认证密钥
        //  End;
    }

函数调用:
        //发检查卡
        //Function MadeCheck(CommHandle: THandle; TRK: TRootKey; Var i_Error: Integer):
        //                   Boolean; StdCall; External 'EleMeter.DLL';
        [DllImport("EleMeter.dll")]
        private static extern bool MadeCheck(int THalde, RootKey rootKey, ref int iError);
        public string fnMakeCheck(RootKey rootKey)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = MadeCheck(m_hCardHandle, rootKey, ref iError);
                if (!isOK)
                {
                    strErrorInfo = fnGetError(iError);
                }
            }
            catch (Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;

        }

        //读检查卡
        //Function ReadCheck(CommHandle: THandle; CheckReturn: PCheckReturn; Var i_Error:
        //                   Integer): Boolean; StdCall; External 'EleMeter.DLL';
        [DllImport("EleMeter.dll")]
        private static extern bool ReadCheck(int THandle, IntPtr checkReturnPtr, ref int iError);
        public string fnReadCheck(IntPtr checkReturnPtr)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = ReadCheck(m_hCardHandle, checkReturnPtr, ref iError);
                if (!isOK)
                    strErrorInfo = fnGetError(iError);
            }
            catch(Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;
        }

现在我在C#中调用上面的函数
        public void fnCheckCardRead()
        {
            CheckReturn tcr = new CheckReturn();
            tcr.init();//初始化结构体数据
            string strRet = "";
            IntPtr checkReturnPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tcr));
            Marshal.StructureToPtr(tcr, checkReturnPtr, true);
            strRet = m_ICCard.fnReadCheck(checkReturnPtr);
            if (strRet == "")
            {
                MessageBox.Show("读检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        }
        public void fnCheckCardMake()
        {
            RootKey rootKey = new RootKey();
            ICCardHelper.init(ref rootKey);//初始化结构体数据
            string strRet;
            strRet = m_ICCard.fnMakeCheck(rootKey);
            if (strRet.Length == 0)
            {
                MessageBox.Show("发检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        }
结果读卡的函数成功了,但是checkReturn结构体中的数据没有任何变化,
而发卡程序也错了。
这个好像是因为C#中的结构体跟Dephi中的Record有区别才造成的吧?还是我调用的时候出错了?

27 个解决方案

#1


 [DllImport("EleMeter.dll")] 
        private static extern bool ReadCheck(int THandle, ref CheckReturn CR, ref int iError); 

CheckReturn  CB=new CheckReturn ();
isOK = ReadCheck(m_hCardHandle, ref CB, ref iError); 


#2


引用 1 楼 wartim 的回复:
[DllImport("EleMeter.dll")]
        private static extern bool ReadCheck(int THandle, ref CheckReturn CR, ref int iError);

CheckReturn  CB=new CheckReturn ();
isOK = ReadCheck(m_hCardHandle, ref CB, ref iError);

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

#3


先帮顶

#4


是不是传参数时应该加上ref 来传递引用,没仔细看你的code,你可以将需要带回值的参数前加上ref试试

public string fnReadCheck(IntPtr checkReturnPtr)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = ReadCheck(m_hCardHandle,  ref checkReturnPtr, ref iError);
                if (!isOK)
                    strErrorInfo = fnGetError(iError);
            }
            catch(Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;
        }

现在我在C#中调用上面的函数
        public void fnCheckCardRead()
        {
            CheckReturn tcr = new CheckReturn();
            tcr.init();//初始化结构体数据
            string strRet = "";
            IntPtr checkReturnPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tcr));
            Marshal.StructureToPtr(tcr, checkReturnPtr, true);
            strRet = m_ICCard.fnReadCheck( ref checkReturnPtr);
            if (strRet == "")
            {
                MessageBox.Show("读检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        }
        public void fnCheckCardMake()
        {
            RootKey rootKey = new RootKey();
            ICCardHelper.init(ref rootKey);//初始化结构体数据
            string strRet;
            strRet = m_ICCard.fnMakeCheck(rootKey);
            if (strRet.Length == 0)
            {
                MessageBox.Show("发检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        } 

#5


把C#中对应的结构体中定义成与Dephi的Record完全一样(只含有成员,不含有方法,并且数据排列与之相同),再用ref传递过去,调试的时候还是出现了错误信息:
====================================================================================
运行库遇到了错误。此错误的地址为 0x79e7e5a6,在线程 0xdf8 上。错误代码为 0xc0000005。此错误可能是 CLR 中的 bug,或者是用户代码的不安全部分或不可验证部分中的 bug。此 bug 的常见来源包括用户对 COM-interop 或 PInvoke 的封送处理错误,这些错误可能会损坏堆栈。
====================================================================================
请问这个问题怎么解决?

#6


 我将函数参数设置成指针形式并且用ref标记进行处理,能够调用成功了,但是没有按预期完成,checkReturn中的字符串都不见了。。。。别的字段读上来的值也不正确。
       [DllImport("EleMeter.dll")]
        private static extern bool ReadCheck(int THandle, ref IntPtr checkReturnPtr, ref int iError);
        //private static extern bool ReadCheck(int THandle, ref CheckReturn checkReturn, ref int iError);
        //public string fnReadCheck(ref CheckReturn checkReturn)
        public string fnReadCheck(ref IntPtr checkReturnPtr)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = ReadCheck(m_hCardHandle, ref checkReturnPtr, ref iError);
                if (!isOK)
                    strErrorInfo = fnGetError(iError);
            }
            catch(Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;
        }
调用的时候:
           CheckReturn tcr = new CheckReturn();
            ICCardHelper.init(ref tcr);
            string strRet = "";
            IntPtr checkReturnPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tcr));
            Marshal.StructureToPtr(tcr, checkReturnPtr, false);
            strRet = m_ICCard.fnReadCheck(ref checkReturnPtr);

读之前:

-tcr {ICCardLibrary_HuaBei.CheckReturn} ICCardLibrary_HuaBei.CheckReturn
dAlarm1 9.9 double
dAlarm2 9.9 double
dApex 9.9 double
dCalm 9.9 double
dFreeze1 9.9 double
dFreeze2 9.9 double
dFreeze3 9.9 double
dInputValue 9.9 double
dLeft 9.9 double
dOverall 9.9 double
dOverValue 9.9 double
dReverse 9.9 double
dSumBuy 9.9 double
dTine 9.9 double
dVale 9.9 double
iTimes 9 int
+ strDate {char[6]} char[]
+ strFreezeTime {char[2]} char[]
+ strMark {char[2]} char[]
+ strMeterNo {char[12]} char[]
+ strState {char[2]} char[]
+ strUserNo {char[12]} char[]

读之后:
-tcr {ICCardLibrary_HuaBei.CheckReturn} ICCardLibrary_HuaBei.CheckReturn
dAlarm1 9.8999999999068677 double
dAlarm2 -4310085580882.0 double
dApex -0.00000000000094587448984381228 double
dCalm 9.89999999993597 double
dFreeze1 0.0 double
dFreeze2 9.8999999999359662 double
dFreeze3 -2.3534373682644015E-185 double
dInputValue 0.0 double
dLeft 0.0 double
dOverall -2.3149085788054889E-148 double
dOverValue 9.8999999999359645 double
dReverse 9.899999999935968 double
dSumBuy 9.8999999999068677 double
dTine 9.899999999935968 double
dVale -1.7003920768336167E+296 double
iTimes 48 int












#7


帮顶

#8


ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不用stringbulder而用ref char[]照样可以,有时又一个byte[]传过去不用ref也可以返回值,好像和delphi/vc里的写法和调用规则也有关系

这种问题是比较麻烦,只能你自己多测试了,

#9


引用 8 楼 wartim 的回复:
ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不用stringbulder而用ref char[]照样可以,有时又一个byte[]传过去不用ref也可以返回值,好像和delphi/vc里的写法和调用规则也有关系

这种问题是比较麻烦,只能你自己多测试了,

谢谢了,好像Delphi中的记录类型与C#中的结构体存储方式也不相同,C#中可以做到对struct中的元素强制分配内存和排序,但Delphi中的记录类型怎么分配内存我不知道,所以还是没法统一,而我用上面的方法去调用之后发现用ref checkReturnPtr和ref checkReturn返回的结果其实是一样的,不知道到底是哪出问题了。。。。。。

#10


要在delphi中更改接口,才能够调用成功。

#11


不会啊,帮顶吧

#12


遇到和楼主一样的问题,灾难,搞了两天了还没结果,要是楼主解决了说一声啊,谢谢

#13


晕死了,这个东西最简单的办法还是改接口。。。反正我试了好多方法都没法成功,你可以用unsafe的指针变量试试,我用的那个接口没法解决,后来对方改了接口才搞定。

#14


JFJF

#15


最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

#16


引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

接口是别人提供的,而且发球保密内容,无法自己改。。。

#17


引用 9 楼 jiangzhu1212 的回复:
引用 8 楼 wartim 的回复:
ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不……


肯定是要清楚Dephi的struct的存放方式,不然数据容易出现问题,出现偏移之类的

引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。


这个同意,既然写成DLL供别人调用,那最好是只使用C语言的基本数据类型,这样才方便跨平台调用,不能要求别人都使用Delphi调用.

#18


我是delphi程序员,给楼主一点提示:
delphi中的record有两种分配内存方式,这和C不一样,如果要按实际的内存分配,要加上packed关键字:
  type
    TMyRec =  packed record
      a: integer;
      b: string[20];
    end;

如果定义成下面这样:
  type
    TMyRec2 = record
      a: integer;
      b: string[20];
    end;

那么,你会发现 SizeOf(TmyRec) 和 SizeOf(YmyRec2) 其实是不一样的。
还有,成员变量如果有String,一定要指定长度。

#19


引用 18 楼 shaoyy 的回复:
我是delphi程序员,给楼主一点提示:
delphi中的record有两种分配内存方式,这和C不一样,如果要按实际的内存分配,要加上packed关键字:
  type
  TMyRec = packed record
  a: integer;
  b: string[20];
  end;

如果定义成下面这样:
  type
  TMyRec2 = record
  a……

#20


引用 16 楼 jiangzhu1212 的回复:
引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

接口是别人提供的,而且发球保密内容,无法自己改。。。


悲剧啊!我也遇到了和LZ一样的问题啊!需要做个消费刷卡的系统!现在就在悲剧中啊!

#21


pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!

#22


引用 21 楼 ddc100565 的回复:
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!


pchar就是一个指针,用IntPtr就行了

#23


难啊,不解释

#24


引用 22 楼 shaoyy 的回复:
引用 21 楼 ddc100565 的回复:
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!


pchar就是一个指针,用IntPtr就行了


原来是这样的:
	BOOL writerfMechMn(port:integer;mm:pchar)

我用C#引用:
 //功能:设置读卡器密码
        //参数:port: 串口号 mm : 12为密码符
        //返回:是否成功(BOOLEAN类型)
        [DllImport("xfic.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool writerfMechMn(int port ,IntPtr mm);


在调用的时候:
  IntPtr pp = new IntPtr(2);
            textBox1.Text = Class1.writerfMechMn(port, pp).ToString();


可是还是报错,说是找不到入口点!怎么回事啊?

#25


有这么多人在使用握奇数据的链接库呀

#26


该回复于2011-04-02 09:35:03被版主删除

#27


有这么多功夫,可以让你老板找个人用.net写设备驱动,不引用delphi的东西。

#1


 [DllImport("EleMeter.dll")] 
        private static extern bool ReadCheck(int THandle, ref CheckReturn CR, ref int iError); 

CheckReturn  CB=new CheckReturn ();
isOK = ReadCheck(m_hCardHandle, ref CB, ref iError); 


#2


引用 1 楼 wartim 的回复:
[DllImport("EleMeter.dll")]
        private static extern bool ReadCheck(int THandle, ref CheckReturn CR, ref int iError);

CheckReturn  CB=new CheckReturn ();
isOK = ReadCheck(m_hCardHandle, ref CB, ref iError);

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

#3


先帮顶

#4


是不是传参数时应该加上ref 来传递引用,没仔细看你的code,你可以将需要带回值的参数前加上ref试试

public string fnReadCheck(IntPtr checkReturnPtr)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = ReadCheck(m_hCardHandle,  ref checkReturnPtr, ref iError);
                if (!isOK)
                    strErrorInfo = fnGetError(iError);
            }
            catch(Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;
        }

现在我在C#中调用上面的函数
        public void fnCheckCardRead()
        {
            CheckReturn tcr = new CheckReturn();
            tcr.init();//初始化结构体数据
            string strRet = "";
            IntPtr checkReturnPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tcr));
            Marshal.StructureToPtr(tcr, checkReturnPtr, true);
            strRet = m_ICCard.fnReadCheck( ref checkReturnPtr);
            if (strRet == "")
            {
                MessageBox.Show("读检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        }
        public void fnCheckCardMake()
        {
            RootKey rootKey = new RootKey();
            ICCardHelper.init(ref rootKey);//初始化结构体数据
            string strRet;
            strRet = m_ICCard.fnMakeCheck(rootKey);
            if (strRet.Length == 0)
            {
                MessageBox.Show("发检查卡成功!");
            }
            else
            {
                MessageBox.Show(strRet);
            }
        } 

#5


把C#中对应的结构体中定义成与Dephi的Record完全一样(只含有成员,不含有方法,并且数据排列与之相同),再用ref传递过去,调试的时候还是出现了错误信息:
====================================================================================
运行库遇到了错误。此错误的地址为 0x79e7e5a6,在线程 0xdf8 上。错误代码为 0xc0000005。此错误可能是 CLR 中的 bug,或者是用户代码的不安全部分或不可验证部分中的 bug。此 bug 的常见来源包括用户对 COM-interop 或 PInvoke 的封送处理错误,这些错误可能会损坏堆栈。
====================================================================================
请问这个问题怎么解决?

#6


 我将函数参数设置成指针形式并且用ref标记进行处理,能够调用成功了,但是没有按预期完成,checkReturn中的字符串都不见了。。。。别的字段读上来的值也不正确。
       [DllImport("EleMeter.dll")]
        private static extern bool ReadCheck(int THandle, ref IntPtr checkReturnPtr, ref int iError);
        //private static extern bool ReadCheck(int THandle, ref CheckReturn checkReturn, ref int iError);
        //public string fnReadCheck(ref CheckReturn checkReturn)
        public string fnReadCheck(ref IntPtr checkReturnPtr)
        {
            string strErrorInfo = "";
            try
            {
                fnOpenCom();
                bool isOK;
                int iError = 0;
                isOK = ReadCheck(m_hCardHandle, ref checkReturnPtr, ref iError);
                if (!isOK)
                    strErrorInfo = fnGetError(iError);
            }
            catch(Exception exc)
            {
                strErrorInfo = exc.Message;
            }
            finally
            {
                fnCloseCom();
            }
            return strErrorInfo;
        }
调用的时候:
           CheckReturn tcr = new CheckReturn();
            ICCardHelper.init(ref tcr);
            string strRet = "";
            IntPtr checkReturnPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tcr));
            Marshal.StructureToPtr(tcr, checkReturnPtr, false);
            strRet = m_ICCard.fnReadCheck(ref checkReturnPtr);

读之前:

-tcr {ICCardLibrary_HuaBei.CheckReturn} ICCardLibrary_HuaBei.CheckReturn
dAlarm1 9.9 double
dAlarm2 9.9 double
dApex 9.9 double
dCalm 9.9 double
dFreeze1 9.9 double
dFreeze2 9.9 double
dFreeze3 9.9 double
dInputValue 9.9 double
dLeft 9.9 double
dOverall 9.9 double
dOverValue 9.9 double
dReverse 9.9 double
dSumBuy 9.9 double
dTine 9.9 double
dVale 9.9 double
iTimes 9 int
+ strDate {char[6]} char[]
+ strFreezeTime {char[2]} char[]
+ strMark {char[2]} char[]
+ strMeterNo {char[12]} char[]
+ strState {char[2]} char[]
+ strUserNo {char[12]} char[]

读之后:
-tcr {ICCardLibrary_HuaBei.CheckReturn} ICCardLibrary_HuaBei.CheckReturn
dAlarm1 9.8999999999068677 double
dAlarm2 -4310085580882.0 double
dApex -0.00000000000094587448984381228 double
dCalm 9.89999999993597 double
dFreeze1 0.0 double
dFreeze2 9.8999999999359662 double
dFreeze3 -2.3534373682644015E-185 double
dInputValue 0.0 double
dLeft 0.0 double
dOverall -2.3149085788054889E-148 double
dOverValue 9.8999999999359645 double
dReverse 9.899999999935968 double
dSumBuy 9.8999999999068677 double
dTine 9.899999999935968 double
dVale -1.7003920768336167E+296 double
iTimes 48 int












#7


帮顶

#8


ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不用stringbulder而用ref char[]照样可以,有时又一个byte[]传过去不用ref也可以返回值,好像和delphi/vc里的写法和调用规则也有关系

这种问题是比较麻烦,只能你自己多测试了,

#9


引用 8 楼 wartim 的回复:
ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不用stringbulder而用ref char[]照样可以,有时又一个byte[]传过去不用ref也可以返回值,好像和delphi/vc里的写法和调用规则也有关系

这种问题是比较麻烦,只能你自己多测试了,

谢谢了,好像Delphi中的记录类型与C#中的结构体存储方式也不相同,C#中可以做到对struct中的元素强制分配内存和排序,但Delphi中的记录类型怎么分配内存我不知道,所以还是没法统一,而我用上面的方法去调用之后发现用ref checkReturnPtr和ref checkReturn返回的结果其实是一样的,不知道到底是哪出问题了。。。。。。

#10


要在delphi中更改接口,才能够调用成功。

#11


不会啊,帮顶吧

#12


遇到和楼主一样的问题,灾难,搞了两天了还没结果,要是楼主解决了说一声啊,谢谢

#13


晕死了,这个东西最简单的办法还是改接口。。。反正我试了好多方法都没法成功,你可以用unsafe的指针变量试试,我用的那个接口没法解决,后来对方改了接口才搞定。

#14


JFJF

#15


最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

#16


引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

接口是别人提供的,而且发球保密内容,无法自己改。。。

#17


引用 9 楼 jiangzhu1212 的回复:
引用 8 楼 wartim 的回复:
ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

也许是你checkReturnPtr c#里的定义写得问题

不行啊,还是同样有问题,传递过去的要是满足那个结构的地址才对吧?像stringBuilder对应Dephi中的char*

引用就是地址,地址一般都是ref过去的,有时char*不……


肯定是要清楚Dephi的struct的存放方式,不然数据容易出现问题,出现偏移之类的

引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。


这个同意,既然写成DLL供别人调用,那最好是只使用C语言的基本数据类型,这样才方便跨平台调用,不能要求别人都使用Delphi调用.

#18


我是delphi程序员,给楼主一点提示:
delphi中的record有两种分配内存方式,这和C不一样,如果要按实际的内存分配,要加上packed关键字:
  type
    TMyRec =  packed record
      a: integer;
      b: string[20];
    end;

如果定义成下面这样:
  type
    TMyRec2 = record
      a: integer;
      b: string[20];
    end;

那么,你会发现 SizeOf(TmyRec) 和 SizeOf(YmyRec2) 其实是不一样的。
还有,成员变量如果有String,一定要指定长度。

#19


引用 18 楼 shaoyy 的回复:
我是delphi程序员,给楼主一点提示:
delphi中的record有两种分配内存方式,这和C不一样,如果要按实际的内存分配,要加上packed关键字:
  type
  TMyRec = packed record
  a: integer;
  b: string[20];
  end;

如果定义成下面这样:
  type
  TMyRec2 = record
  a……

#20


引用 16 楼 jiangzhu1212 的回复:
引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

接口是别人提供的,而且发球保密内容,无法自己改。。。


悲剧啊!我也遇到了和LZ一样的问题啊!需要做个消费刷卡的系统!现在就在悲剧中啊!

#21


pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!

#22


引用 21 楼 ddc100565 的回复:
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!


pchar就是一个指针,用IntPtr就行了

#23


难啊,不解释

#24


引用 22 楼 shaoyy 的回复:
引用 21 楼 ddc100565 的回复:
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!


pchar就是一个指针,用IntPtr就行了


原来是这样的:
	BOOL writerfMechMn(port:integer;mm:pchar)

我用C#引用:
 //功能:设置读卡器密码
        //参数:port: 串口号 mm : 12为密码符
        //返回:是否成功(BOOLEAN类型)
        [DllImport("xfic.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool writerfMechMn(int port ,IntPtr mm);


在调用的时候:
  IntPtr pp = new IntPtr(2);
            textBox1.Text = Class1.writerfMechMn(port, pp).ToString();


可是还是报错,说是找不到入口点!怎么回事啊?

#25


有这么多人在使用握奇数据的链接库呀

#26


该回复于2011-04-02 09:35:03被版主删除

#27


有这么多功夫,可以让你老板找个人用.net写设备驱动,不引用delphi的东西。