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

jiangzhu1212 2009-10-29 02:16:45
==================================================================================
接口中的数据结构定义

//查询卡返写区结构
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有区别才造成的吧?还是我调用的时候出错了?
...全文
718 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
有这么多功夫,可以让你老板找个人用.net写设备驱动,不引用delphi的东西。
开发者孙小聪 2011-04-01
  • 打赏
  • 举报
回复
有这么多人在使用握奇数据的链接库呀
ddc100565 2010-04-19
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 shaoyy 的回复:]
引用 21 楼 ddc100565 的回复:
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!


pchar就是一个指针,用IntPtr就行了
[/Quote]

原来是这样的:
	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();


可是还是报错,说是找不到入口点!怎么回事啊?
wjz748305545 2010-04-17
  • 打赏
  • 举报
回复
难啊,不解释
shaoyy 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 ddc100565 的回复:]
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!
[/Quote]

pchar就是一个指针,用IntPtr就行了
ddc100565 2010-04-16
  • 打赏
  • 举报
回复
pchar 在c#中可以用什么来代替啊?网上说使用StringBuilder ,我试了不行啊!
ddc100565 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 jiangzhu1212 的回复:]
引用 15 楼 oushengfen 的回复:
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。

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

悲剧啊!我也遇到了和LZ一样的问题啊!需要做个消费刷卡的系统!现在就在悲剧中啊!
zhang1986_11 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 shaoyy 的回复:]
我是delphi程序员,给楼主一点提示:
delphi中的record有两种分配内存方式,这和C不一样,如果要按实际的内存分配,要加上packed关键字:
type
TMyRec = packed record
a: integer;
b: string[20];
end;

如果定义成下面这样:
type
TMyRec2 = record
a……
[/Quote]
shaoyy 2010-04-15
  • 打赏
  • 举报
回复
我是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,一定要指定长度。
xingyuebuyu 2010-04-13
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 jiangzhu1212 的回复:]
引用 8 楼 wartim 的回复:
ref IntPtr checkReturnPtr ?
那不等同 checkReturn **P 了

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

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

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

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

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

这个同意,既然写成DLL供别人调用,那最好是只使用C语言的基本数据类型,这样才方便跨平台调用,不能要求别人都使用Delphi调用.
jiangzhu1212 2010-04-13
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 oushengfen 的回复:]
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。
[/Quote]
接口是别人提供的,而且发球保密内容,无法自己改。。。
jiangzhu1212 2010-04-09
  • 打赏
  • 举报
回复
晕死了,这个东西最简单的办法还是改接口。。。反正我试了好多方法都没法成功,你可以用unsafe的指针变量试试,我用的那个接口没法解决,后来对方改了接口才搞定。
oushengfen 2010-04-09
  • 打赏
  • 举报
回复
最好使用标准一点的,如Delphi的string对于其它语言不好进行调用,建议使用pchar之类的数据类型。
Delphi的结构有两种,一种是按最大成员分配长度,一个是紧凑型。自己再详细了解一下。
foxwfb 2010-04-09
  • 打赏
  • 举报
回复
JFJF
lee_3do 2009-11-25
  • 打赏
  • 举报
回复
遇到和楼主一样的问题,灾难,搞了两天了还没结果,要是楼主解决了说一声啊,谢谢
jiangzhu1212 2009-11-07
  • 打赏
  • 举报
回复
要在delphi中更改接口,才能够调用成功。
lerit 2009-11-07
  • 打赏
  • 举报
回复
不会啊,帮顶吧
yanlongwuhui 2009-10-30
  • 打赏
  • 举报
回复
帮顶
jiangzhu1212 2009-10-30
  • 打赏
  • 举报
回复
我将函数参数设置成指针形式并且用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












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

110,547

社区成员

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

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

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