模块“MpLib.dll”中地址003B0E8E处的访问冲突。读取地址00120BF4

时间:2012-10-21 01:40:17

标签: delphi delphi-xe

我在Stackoverflow上搜索了我遇到的问题,但它们都非常具体针对特定的访问冲突。

我相信我遇到问题的代码是一个名为MpqExtractFile的函数,存储在DLL中。

功能:

function MpqExtractFile(var hMPQ: Integer; szToExtract, szExtracted: AnsiString): Boolean; stdcall; external 'MpqLib.dll' name 'B2';

拨打:

if MpqExtractFile(hMPQ, 'war3map.j', AnsiString(tempDir+'\war3map.j')) = True
then ShowMessage('Success.')
else ShowMessage('Failed.');

执行此代码后,我的应用程序会抛出访问冲突错误,因此根本不会显示ShowMessage

我不确定上述内容是否足以估计问题所在,但如果还有什么我应该告诉我。

修改

这是我一直在解释的VB.NET源代码的摘录:

Declare Function MpqExtractFile Lib "MpqLib.dll" Alias "B2" (ByVal hMPQ As Integer, ByVal szToExtract As String, ByVal szExtracted As String) As Boolean

我显然不熟悉其他语言的声明,但我在声明VB函数的同一个VB文件中找到了下面的函数。

BOOL WINAPI MpqExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted);

先谢谢你了!

2 个答案:

答案 0 :(得分:7)

AnsiString是完全错误的类型,除非DLL在Delphi / C ++ Builder中写入并且在其参数中实际使用了AnsiString。如果是这种情况,您需要知道DLL编写的Delphi / C ++ Builder版本,因为AnsiString的内存布局在2009年发生了变化。

在任何情况下,跨DLL边界传递非POD数据是非常危险的,因此大多数DLL都不会这样做。相关参数很可能是PAnsiChar,例如:

function MpqExtractFile(var hMPQ: Integer; szToExtract, szExtracted: PAnsiChar): Boolean; stdcall; external 'MpqLib.dll' name 'B2'; 

if MpqExtractFile(hMPQ, 'war3map.j', PAnsiChar(AnsiString(tempDir+'\war3map.j'))) then
  ShowMessage('Success.') 
else
  ShowMessage('Failed.'); 

需要考虑的其他要点:

1)并非所有DLL都使用stdcall调用约定。对于使用cdecl调用约定而言,用C语言编写的DLL(例如许多开源库)并不罕见:

function MpqExtractFile(var hMPQ: Integer; szToExtract, szExtracted: PAnsiChar): Boolean; cdecl; external 'MpqLib.dll' name 'B2'; 

2)C没有真正的Boolean数据类型,如Delphi和C ++。 C代码使用Byte甚至Integer来模仿Boolean的情况并不少见。

为了在Delphi中使用DLL,您确实需要知道其导出函数的实际适当声明。这在C / C ++中不是一个问题,因为大多数DLL都有一个附带的.h文件来提供声明。你有这样的.h文件吗?如果是这样,请在此处发布,以便有人可以验证您对Delphi的翻译。

<强>更新

基于新信息,正确的Delphi声明是这样的:

function MpqExtractFile(hMpq: THandle; const szToExtract, szExtracted: PAnsiChar): BOOL; stdcall; external 'MpqLib.dll' name 'B2';

答案 1 :(得分:4)

您的VB.net声明是:

Declare Function MpqExtractFile Lib "MpqLib.dll" Alias "B2" (
    ByVal hMPQ As Integer, ByVal szToExtract As String, 
    ByVal szExtracted As String) As Boolean

等效的Delphi导入将是:

function MpqExtractFile(MpqExtractFile: Integer; 
    szToExtract, szExtracted: PAnsiChar): BOOL; 
    stdcall; external 'MpqLib.dll' name 'B2';

Delphi字符串类型不应用于互操作。 p / invoke marshaller将String映射到C ++ char *,这是Delphi中的PAnsiChar。

这种任务确实应该用C ++头文件来执行。你说你没有那个。如果DLL是用C ++编写的,那么头文件肯定存在。跟踪它并支付它作为你的来源是值得的。