如何使用Delphi从外部DLL中提取Packed Record中的数据?

时间:2015-07-07 19:14:49

标签: 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 = 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在RECV_PACKET中发送memory addressMessage.LParam。 因此,我希望使用ResBlock获取Message.LParam的数据。 但我写的代码只是发送破碎的数据。 我想从中获取纯数据。我能怎么做?

接收消息程序如下:

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;

更新:

原始API定义如下:

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;

1 个答案:

答案 0 :(得分:2)

我们没有您正在查看的文档。但我确实找到this online document(不是英文),以及this header file,以及VB,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;

type
  TForm1 = class(TForm)
  private
    procedure OnReceiveData(var Message: TMessage); message WM_USER + XM_RECEIVE_DATA;
    ...
  end;

procedure TForm1.OnReceiveData(var Message: TMessage);
var
  recvPacket: LPRECV_PACKET;
  _resBlock: LPResBlock;
  msgPacket: LPMSG_PACKET;
begin
  case Message.WParam of
    REQUEST_DATA: begin
      recvPacket := LPRECV_PACKET(Message.LParam);
      // make sure recvPacket^.nDataLength is actually >= SizeOf(ResBlock)
      // before accessing the data...
      _resBlock := LPResBlock(recvPacket^.lpData);
      ShowMessage(_resBlock^.title);
    end;
    MESSAGE_DATA: begin
      msgPacket := LPMSG_PACKET(Message.LParam);
      //...
      ETK_ReleaseMessageData(Message.LParam);
    end;
    SYSTEM_ERROR_DATA: begin
      msgPacket := LPMSG_PACKET(Message.LParam);
      //...
      ETK_ReleaseMessageData(Message.LParam);
    end;
    RELEASE_DATA: begin
      //...
      ETK_ReleaseRequestData(Message.LParam);
    end;
  end;
end;