将 GlobalPlatform 从 C 翻译成 Delphi - 访问冲突错误
Translating GlobalPlatform from C to Delphi - Access violation errors
我想在 Delphi 中使用 kaoh Karsten Ohme 中的 GlobalPlatform.dll。所以我尝试翻译 headers 以便我可以在 Delphi.
中使用 GlobalPlatform.dll
我翻译的第一个是Connection.h,i uploaded it on pastebin here。
我翻译的第二个是 Security.h i uploaded it on pastebin here.
首先,我使用 OPGP_establish_context
函数建立了一个上下文,这似乎没问题,因为结果是 OPGP_ERROR_STATUS_SUCCESS
并且消息还显示“成功”。
但随后我尝试使用 OPGP_list_readers
函数列出 readers,这也 returns 成功 - 但是当我尝试读取返回的名称时,我获得了各种访问权限违规(主要在 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;
当我使用上面的代码时,我没有收到任何错误,但是当我取消注释消息框时 - 我遇到了访问冲突。我整天都在尝试,我修改了所有内容..但没有运气。我看不出我做错了什么。也许有人可以帮助我并指出正确的方向。我了解 adress 00000000
上的访问冲突意味着什么,但我不知道我是否以正确的方式翻译了 headers 可能导致错误的原因。
如果有人可以帮助我检查或自行测试 - 将不胜感激。
我正在使用 Delphi 10.4,并且我有一个内部智能卡 reader(在笔记本电脑中)、一个 Omnikey 智能卡 reader 和另一个未知品牌。
ps。是的,我知道 GPSshell 命令行实用程序,但我想避免使用它。我想使用智能卡来确保安全,而对命令行工具的需求会使这成为一个弱点 - 因此我想直接使用库。
在您翻译的第一条记录中,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 个字符。这是因为 array declaration in Delphi 定义了数组的 indexes,所以在您的情况下,您声明数组具有索引 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
文件建议将 non-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
字段),否则将被错误处理。
我想在 Delphi 中使用 kaoh Karsten Ohme 中的 GlobalPlatform.dll。所以我尝试翻译 headers 以便我可以在 Delphi.
中使用 GlobalPlatform.dll我翻译的第一个是Connection.h,i uploaded it on pastebin here。
我翻译的第二个是 Security.h i uploaded it on pastebin here.
首先,我使用 OPGP_establish_context
函数建立了一个上下文,这似乎没问题,因为结果是 OPGP_ERROR_STATUS_SUCCESS
并且消息还显示“成功”。
但随后我尝试使用 OPGP_list_readers
函数列出 readers,这也 returns 成功 - 但是当我尝试读取返回的名称时,我获得了各种访问权限违规(主要在 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;
当我使用上面的代码时,我没有收到任何错误,但是当我取消注释消息框时 - 我遇到了访问冲突。我整天都在尝试,我修改了所有内容..但没有运气。我看不出我做错了什么。也许有人可以帮助我并指出正确的方向。我了解 adress 00000000
上的访问冲突意味着什么,但我不知道我是否以正确的方式翻译了 headers 可能导致错误的原因。
如果有人可以帮助我检查或自行测试 - 将不胜感激。
我正在使用 Delphi 10.4,并且我有一个内部智能卡 reader(在笔记本电脑中)、一个 Omnikey 智能卡 reader 和另一个未知品牌。
ps。是的,我知道 GPSshell 命令行实用程序,但我想避免使用它。我想使用智能卡来确保安全,而对命令行工具的需求会使这成为一个弱点 - 因此我想直接使用库。
在您翻译的第一条记录中,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 个字符。这是因为 array declaration in Delphi 定义了数组的 indexes,所以在您的情况下,您声明数组具有索引 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
文件建议将 non-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
字段),否则将被错误处理。