eXX*_*tor 0 c++ delphi dll smartcard globalplatform
我想在 Delphi 中使用kaoh Karsten Ohme的 GlobalPlatform.dll 。所以我尝试翻译标头,以便我可以在 Delphi 中使用 GlobalPlatform.dll。
我翻译的第一个是Connection.h,我将其上传到pastebin 这里。
我翻译的第二个是Security.h,我将其上传到pastebin。
首先,我与该OPGP_establish_context函数建立了一个上下文,这似乎进展顺利,因为结果是 aOPGP_ERROR_STATUS_SUCCESS并且消息还指出“成功”。
但后来我尝试列出具有该OPGP_list_readers函数的读者,该函数也返回成功 - 但是当我尝试读取返回的名称时,我遇到了各种访问冲突(主要是在adress 00000000 and trying to read 00000000,但我的尝试之间存在差异)。
我的代码分配给按钮单击:
procedure TfrmFormatCard.Button1Click(Sender: TObject);
const
BUFLEN = 1024;
var
Status,
Status2 : OPGP_ERROR_STATUS;
Context : OPGP_CARD_CONTEXT;
Names : array [0..BUFLEN +1] of Char;
Len : DWord;
begin
Context.libraryName := 'gppcscconnectionplugin';
Context.libraryVersion := '211';
Status := OPGP_establish_context(Context);
if Status.errorStatus = OPGP_ERROR_STATUS_SUCCESS then
begin
Len := 1024;
Status2 := OPGP_list_readers(Context, Names, Len);
if Status2.errorStatus = OPGP_ERROR_STATUS_SUCCESS then
begin
// Messagebox(application.Handle, names, '', 0);
end;
OPGP_release_context(Context);
end;
end;
Run Code Online (Sandbox Code Playgroud)
当我使用上面的代码时,我没有收到任何错误,但是当我取消注释消息框时 - 我收到访问冲突。我一整天都在尝试,我修改了所有内容..但没有运气。我看不出我做错了什么。也许有人可以帮助我并指出我正确的方向。我了解访问冲突的含义adress 00000000,但我不知道我是否以正确的方式翻译了标头,这可能会导致错误。
如果有人可以通过检查或自己测试来帮助我 - 那将不胜感激。
我使用的是 Delphi 10.4,并且有一个内部智能卡读卡器(在笔记本电脑中)、一个 Omnikey 智能卡读卡器和另一个未知品牌。
附:是的,我知道 GPShell 命令行实用程序,但我想避免使用它。我想使用智能卡来确保安全,而对命令行工具的需求将使这成为一个弱点 - 因此我想直接使用该库。
在您翻译的第一条记录中OPGP_ERROR_STATUS,该errorMessage字段在 C 代码中声明为:
TCHAR errorMessage[ERROR_MESSAGE_LENGTH+1];
Run Code Online (Sandbox Code Playgroud)
其中ERROR_MESSAGE_LENGTH定义为 256,因此该数组最多有257 个字符。
但你的翻译是:
errorMessage : array [0..ERROR_MESSAGE_LENGTH + 1] of Char;
Run Code Online (Sandbox Code Playgroud)
最多258 个字符。这是因为Delphi 中的数组声明定义了数组的索引(包含在内),因此在您的情况下,您将数组声明为具有索引0..257,但它应该是0..256相反的,因此删除+1:
errorMessage : array [0..ERROR_MESSAGE_LENGTH] of Char;
Run Code Online (Sandbox Code Playgroud)
您在翻译记录时OPGP_CARD_CONTEXT也犯了同样的错误:
OPGP_CARD_CONTEXT = record
librarySpecific : Pointer;
libraryName : array [0..64] of Char; // <--
libraryVersion : array [0..32] of Char; // <--
libraryHandle : Pointer;
connectionFunctions : OPGP_CONNECTION_FUNCTIONS;
end;
Run Code Online (Sandbox Code Playgroud)
您声明libraryName有65 个字符,并且libraryVersion声明有33 个字符。它们需要分别为64和32:
OPGP_CARD_CONTEXT = record
librarySpecific : Pointer;
libraryName : array [0..63] of Char;
libraryVersion : array [0..31] of Char;
libraryHandle : Pointer;
connectionFunctions : OPGP_CONNECTION_FUNCTIONS;
end;
Run Code Online (Sandbox Code Playgroud)
根据原始 C 声明:
OPGP_CARD_CONTEXT = record
librarySpecific : Pointer;
libraryName : array [0..63] of Char;
libraryVersion : array [0..31] of Char;
libraryHandle : Pointer;
connectionFunctions : OPGP_CONNECTION_FUNCTIONS;
end;
Run Code Online (Sandbox Code Playgroud)
因此,AV 发生的原因是有道理的,因为OPGP_list_readers()内部访问存储在Context.connectionFunctions数组后面的字段中的函数指针,因此会在错误的内存偏移量处访问指针。
其他需要注意的是TCHAR,它将映射到 或char,wchar_t具体取决于 DLL 的实际编译方式。因此,这可能会也可能不会转化为CharDelphi,具体取决于您使用的版本(您没有说)。一般来说,char-> AnsiChar,wchar_t-> WideChar。该项目的unicode.h文件建议将非 Windows 版本编译为使用char. 但项目 makefile 建议编译 Windows 版本来使用wchar_t。(P)Char因此,在互操作代码中使用并不是一个好主意。根据需要使用(P)AnsiChar或来代替。(P)WideChar
更新
Context另外,在将 传递给 之前,尝试将 的内存清零OPGP_establish_context()。OPGP_establish_context()内部做的第一件事是OPGP_release_context()调用Context,这意味着Context中不能包含任何垃圾(特别是在libraryHandle和connectionFunctions.releaseContext字段中),否则它将被错误处理。