【发布时间】:2022-01-13 01:05:56
【问题描述】:
我需要使用硬件供应商提供的 Delphi 编写的 DLL。在提供的文件中,它提到了以下内容
int ReadCard(char *room, char *gate,char *stime, char *guestname, char *guestid, char *lift, char *track1, char *track2, long *cardno, int *st, int *Breakfast);
对参数的进一步阐述如下:
-
room [out]:字符串指针,接收返回的房间号, 推荐 10 个字节。
-
gate [out]:字符串指针,接收 返回的授权公共门,可以为NULL。
-
客人姓名[出]: 字符串指针,接收返回的客人姓名,可以为NULL。
-
Guestid [out]:字符串指针,接收返回的guest ID, 可以为 NULL。
-
Lift [in]:电梯楼层,字符串参数,“00”代表 默认楼层,“99”代表授权所有楼层, 其他是指定的楼层代码,例如,“010205”代表 01,02,05 三层楼的授权。
-
track1 [out]:接收音轨 1条磁卡数据,可以为NULL。
-
track2 [out]:接收音轨 2 磁卡数据,可以为NULL。
-
Cardno [out]: 长整数 指针,接收返回的卡号,可以为NULL。
-
St [out]:整数 指针,接收返回卡状态:1-正常使用,3-正常 已擦除,4-丢失,5-损坏,6-自动擦除,可以为NULL。 早餐
-
[in]:早餐编号。
这是我的问题 - 在尝试了各种 DLLImport 方法后,我不断收到内存访问冲突错误。
错误内容类似于“System.AccessViolationException:尝试读取或写入受保护的内存这通常表明其他内存已损坏。” ntdll.dll 报错
以下是我尝试过的一些尝试:
[DllImport(DLL_FILE_PATH, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe static extern int ReadCard(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder room,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder gate,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder stayPeriod,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder guestName,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder guestID,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder lift,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder trackData1,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder trackData2,
out Int32[] cardNumber,
out int[] cardStatus,
out int[] breakfast
);
[DllImport(DLL_FILE_PATH, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe static extern int ReadCard(
[MarshalAs(UnmanagedType.LPStr)] string room,
[MarshalAs(UnmanagedType.LPStr)] string gate,
[MarshalAs(UnmanagedType.LPStr)] string stayPeriod,
[MarshalAs(UnmanagedType.LPStr)] string guestName,
[MarshalAs(UnmanagedType.LPStr)] string guestID,
[MarshalAs(UnmanagedType.LPStr)] string lift,
[MarshalAs(UnmanagedType.LPStr)] string trackData1,
[MarshalAs(UnmanagedType.LPStr)] string trackData2,
out long cardNumber,
out long cardStatus,
out long breakfast
);
[DllImport(DLL_FILE_PATH, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe static extern int ReadCard(
out char[] room,
out char[] gate,
out char[] stayPeriod,
out char[] guestName,
out char[] guestID,
out char[] lift,
out char[] trackData1,
out char[] trackData2,
out long[] cardNumber,
out int[] cardStatus,
out int[] breakfast
);
[DllImport(DLL_FILE_PATH, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe static extern int ReadCard(
[MarshalAs(UnmanagedType.LPStr)] out string room,
[MarshalAs(UnmanagedType.LPStr)] out string gate,
[MarshalAs(UnmanagedType.LPStr)] out string stayPeriod,
[MarshalAs(UnmanagedType.LPStr)] out string guestName,
[MarshalAs(UnmanagedType.LPStr)] out string guestID,
[MarshalAs(UnmanagedType.LPStr)] out string lift,
[MarshalAs(UnmanagedType.LPStr)] out string trackData1,
[MarshalAs(UnmanagedType.LPStr)] out string trackData2,
IntPtr cardNumber,
IntPtr cardStatus,
IntPtr breakfast
);
知道我错过了哪里吗?
【问题讨论】:
-
您的意思是用 int32[] cardNumber 替换 long[] cardNumber?我也更新了我的问题。我已经尝试过 StringBuilder 选项,同样,获得内存访问冲突。我注意到 Delphi 是动态数组(索引从零开始)和静态数组,我相信他们的 DLL 使用的是动态数组。由于我们正在处理动态数组,因此分配 new StringBuilder(100) 会限制字符串增长吗?
-
不相关,但我发现
ReadCard函数没有任何参数来指定使用的输出缓冲区的大小并且文档甚至没有提到输出字符串的最大可能长度令人不安(除了房间号,它声明建议使用 10 个字节,但即使这听起来也不是保证,而仅仅是建议)。这是各种缓冲区溢出和安全漏洞的秘诀。看起来是个糟糕的设计。 -
@heapunderrun Delphi 风格的动态数组在这种情况下不起作用,所以不用担心。
-
@heapunderrun 同意,但另一方面,这些特定参数可能正在使用固定长度的缓冲区,其大小在其他地方进行了描述。
-
除了所有其他的cmets,这里不需要unsafe