如何使用Delphi从带有外部DLL的打包记录中提取数据?

如何使用Delphi从带有外部DLL的打包记录中提取数据?,delphi,Delphi,我正在使用外部DLL制作一些delphi程序。 DLL支持向客户端发送窗口消息时发生的请求 我对打包记录的定义如下: type // Message Packet that send from DLL TRECV_PACKET = Packed Record nID: Integer; lpData: Pointer; end; LPRECV_PACKET = ^TRECV_PACKET; // Request record ReqBlock = Pa

我正在使用外部DLL制作一些delphi程序。 DLL支持向客户端发送窗口消息时发生的请求

我对打包记录的定义如下:

type

  // Message Packet that send from DLL
  TRECV_PACKET = Packed Record
    nID: Integer;
    lpData: Pointer;
  end;
  LPRECV_PACKET = ^TRECV_PACKET;

  // Request record
  ReqBlock = Packed Record
    id: array [0..7] of Char
  end;
  LPReqBlock = ^ReqBlock;

  // Response record
  ResBlock = Packed Record
    title: array[0..255] of Char; _dt: Char;
    description: array[0..1204] of Char; _time: Char;
  end;
  LPResBlock = ^ResBlock;
如果我发送请求,DLL将向我的客户端发送窗口消息。 我在文件中找到了一些解释。 DLL在
Message.LParam
中发送
RECV\u数据包的
内存地址。
因此,我想使用
Message.LParam
获取
ResBlock
的数据。 但是我写的代码总是发送坏数据。 我想从中获得纯数据。我该怎么办

接收信息的程序如下:

procedure TForm.OnReceiveData(var Message: TMessage);
var
  recvPacket: LPRECV_PACKET;
  _resBlock: LPResBlock;
begin
  // Actually, I don't know why Message.LParam is parameter of LPRECV_PACKET. How it 
  recvPacket := LPRECV_PACKET(Message.LParam); works? 
  _resBlock := LPResBlock(recvPacket^.lpData);

  ShowMessage(_resBlock^.title); // Broken datas...
end;
function ETK_Request(hWnd: HWND; pszTrCode: PAnsiChar; lpData: Pointer; nDataSize: Integer; bNext: Boolean; pszContinueKey: PAnsiChar; nTimeOut: Integer): Integer; stdcall; external API_DLL;
procedure OnReceiveData(var Message: TMessage); message WM_USER + XM_RECEIVE_DATA;
更新:

原始API定义如下:

procedure TForm.OnReceiveData(var Message: TMessage);
var
  recvPacket: LPRECV_PACKET;
  _resBlock: LPResBlock;
begin
  // Actually, I don't know why Message.LParam is parameter of LPRECV_PACKET. How it 
  recvPacket := LPRECV_PACKET(Message.LParam); works? 
  _resBlock := LPResBlock(recvPacket^.lpData);

  ShowMessage(_resBlock^.title); // Broken datas...
end;
function ETK_Request(hWnd: HWND; pszTrCode: PAnsiChar; lpData: Pointer; nDataSize: Integer; bNext: Boolean; pszContinueKey: PAnsiChar; nTimeOut: Integer): Integer; stdcall; external API_DLL;
procedure OnReceiveData(var Message: TMessage); message WM_USER + XM_RECEIVE_DATA;

我们没有您正在查看的文档。但我确实找到了(不是英文的),以及各种各样的在线例子/翻译,用于VB、C、C和C++。基于这些,您的Delphi代码应该更像这样:

type
  // Message Packet that send from DLL
  TRECV_PACKET = packed record
    nRqID: Integer;
    nDataLength: Integer;
    nTotalDataBufferSize: Integer;
    nElapsedTime: Integer;
    nDataMode: Integer;
    szTrCode: array[0..10] of AnsiChar;
    cCont: array[0..0] of AnsiChar;
    szContKey: array[0..18] of AnsiChar;
    szUserData: array[0..30] of AnsiChar;
    szBlockName: array[0..16] of AnsiChar;
    lpData: PByte;
  end;
  LPRECV_PACKET = ^TRECV_PACKET;

  TMSG_PACKET = packed record
    nRqID: Integer;
    nIsSystemError: Integer;
    szMsgCode: array[0..5] of AnsiChar;
    nMsgLength: Integer;
    lpszMessageData: PByte;
  end;
  LPMSG_PACKET = ^TMSG_PACKET;

  TREAL_RECV_PACKET = packed record
    szTrCode: array[0..3] of AnsiChar;
    nKeyLength: Integer;
    szKeyData: array[0..32] of AnsiChar;
    szRegKey: array[0..32] of AnsiChar;
    nDataLength: Integer;
    pszData: PAnsiChar;
  end;
  LPRECV_REAL_PACKET = ^TRECV_REAL_PACKET;

  // the following records are not documented or defined (where did you get them?),
  // but if the above records are any indication, the fields in these records
  // should be using AnsiChar fields...

  // Request record
  ReqBlock = packed record
    id: array [0..7] of AnsiChar;
  end;
  LPReqBlock = ^ReqBlock;

  // Response record
  ResBlock = packed record
    title: array[0..255] of AnsiChar;
    _dt: AnsiChar;
    description: array[0..1204] of AnsiChar;
    _time: AnsiChar;
  end;
  LPResBlock = ^ResBlock;

...

const
  XM_DISCONNECT = 1;
  XM_RECEIVE_DATA = 3;
  XM_RECEIVE_REAL_DATA = 4;
  XM_LOGIN = 5;
  XM_LOGOUT = 6;
  XM_TIMEOUT_DATA = 7;

const
  REQUEST_DATA = 1;
  MESSAGE_DATA = 2;
  SYSTEM_ERROR_DATA = 3;
  RELEASE_DATA = 4;

function ETK_Request(hParentWnd: HWND; pszTrCode: PAnsiChar; lpData: Pointer; nDataSize: Integer; bNext: BOOL; pszContinueKey: PAnsiChar; nTimeOut: Integer): Integer; stdcall; external API_DLL;
procedure ETK_ReleaseMessageData(lp: LPARAM); stdcall; external API_DLL;
procedure ETK_ReleaseRequestData(nRequestID: Integer); stdcall; external API_DLL;


我已经有一段时间没有处理过这种东西了,但我记得数据类型有问题。您可能需要AnsiChar而不是Char等,但我不确定。我们需要查看原始API定义。如果这是错误的,我们无法对正确的进行反向工程。从DLL中发布函数签名@特拉玛你是对的-我只是根据一些关于DLL的假设猜测。。。等待大卫·赫弗南的出现,并纠正我们的错误;)谢谢已更新原始API定义。此处信息不足。首先也是最明显的:什么是“破碎的数据”?准确地说出你所看到的,以及你希望看到的。如果您使用的是2009年之后发布的Delphi版本,请注意
Char
的含义与
AnsiChar
不同,因此在问题中提及您的Delphi版本可能是谨慎的。您所标记的“原始API定义”并不是这样的。您需要包括用于编写结构定义的源信息。是什么确保这些记录声明是正确的?是的。你是对的。我就是用它工作的。我刚刚更改了stackoverflow的一些代码。所以你把
char
改成了
AnsiChar
对吧。。?我会那样做的。谢谢,我照你说的做了。但我遇到了错误消息。“模块'program.exe'中地址00520267的访问冲突。读取地址000278。”我不知道为什么会显示此消息。@gentlejo:我所做的不仅仅是将
char
更改为
AnsiChar
。我用
lpData
字段前面的更多字段充实了
TRECV_数据包
(从而影响了它在内存中的偏移量),并且在决定将
Message.LParam
强制转换为什么时,我让
OnReceiveData
考虑
Message.WParam
。至于AV错误,它们一直发生在地址0附近,这意味着您可能正在访问未检查的nil指针。除非你能提供官方文件(英文),否则我们在这里就无能为力了。您需要调试代码以查找错误。现在,我可以使用AnsiChar从中获取纯数据。但AV错误也显示出来。所以我在
TRECV\u数据包中打印了每个数据。但是,我只能在
szTrCode
之前获取数据。我无法在
szTrCode
之后获取数据。我想这会导致AV错误。。我不知道为什么API在
szTrCode
之后不发送数据…@gentlejo为什么不进行一些调试?你不能指望我们告诉你你的代码出了什么问题。我们看不到您的代码,也看不到您正在编写的API的规范。考虑拿起电话,打电话给这个API的作者寻求帮助。