我想在Delphi中使用kaoh Karsten Ohme的GlobalPlatform.dll。所以我试着翻译标题,这样我就可以在Delphi中使用GlobalPlatform.dll了。
我翻译的第一个是Connection。h,我把它上传到了这里的pastebin上
我翻译的第二个是Security。h我把它上传到了这里的pastebin上。
首先,我用OPGP_establish_context
函数建立了一个上下文,这似乎很好,因为结果是OPGP_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;
当我使用上面的代码时,我没有得到任何错误,但当我取消注释messagebox时,我得到了访问冲突。我试了一整天,修改了所有内容。。但没有运气。我看不出我做错了什么。也许有人可以帮我,给我指明正确的方向。我理解adress 00000000
上的访问违规意味着什么,但我不知道我是否以正确的方式翻译了标头,这可能会导致错误。
如果有人能帮我检查或自己测试,我将不胜感激。
我使用的是Delphi10.4,我有一个内部智能卡阅读器(在笔记本电脑中(,一个Omnikey智能卡阅读器,还有另一个未知品牌。
ps。是的,我知道GPShell命令行实用程序,但我想避免使用它。我想使用智能卡进行安全保护,而对命令行工具的需求会使这成为一个弱点——因此我想直接使用Library。
在您翻译的第一条记录OPGP_ERROR_STATUS
中,errorMessage
字段在C代码中声明为:
TCHAR errorMessage[ERROR_MESSAGE_LENGTH+1];
其中ERROR_MESSAGE_LENGTH
定义为256,因此此数组具有257个字符最大
但是你的翻译:
errorMessage : array [0..ERROR_MESSAGE_LENGTH + 1] of Char;
最大有258个字符。这是因为Delphi中的数组声明定义了数组的索引(包括在内(,所以在您的情况下,您将数组声明为具有索引0..257
,但它应该是0..256
,因此删除+1
:
errorMessage : array [0..ERROR_MESSAGE_LENGTH] of Char;
你在翻译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;
您正在声明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;
根据原始C声明:
typedef struct {
PVOID librarySpecific; //!< Library specific data.
TCHAR libraryName[64]; //!< The name of the connection library to use.
TCHAR libraryVersion[32]; //!< The version of the connection library to use.
PVOID libraryHandle; //!< The handle to the library.
OPGP_CONNECTION_FUNCTIONS connectionFunctions; //!< Connection functions of the connection library. Is automatically filled in if the connection library can be loaded correctly.
} OPGP_CARD_CONTEXT;
因此,为什么会发生AV是有道理的,因为OPGP_list_readers()
内部访问存储在数组后面的Context.connectionFunctions
字段中的函数指针,因此指针将在错误的内存偏移处访问。
另外需要注意的是TCHAR
,它将映射到char
或wchar_t
,具体取决于DLL的实际编译方式。因此,可能会也可能不会在Delphi中翻译为Char
,这取决于您使用的版本(您没有说(。一般来说,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()
在内部做的第一件事是在Context
上调用OPGP_release_context()
,这意味着Context
中不能包含任何垃圾(特别是在libraryHandle
和connectionFunctions.releaseContext
字段中(,否则它将被错误处理。