将GlobalPlatform从C转换为Delphi-Access冲突错误



我想在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个字符它们需要分别为6432

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,它将映射到charwchar_t,具体取决于DLL的实际编译方式。因此,可能会也可能不会在Delphi中翻译为Char,这取决于您使用的版本(您没有说(。一般来说,char->AnsiCharwchar_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中不能包含任何垃圾(特别是在libraryHandleconnectionFunctions.releaseContext字段中(,否则它将被错误处理。

最新更新