Q&A

  • VC로 제작한 DLL함수 호출 중 파라메터 전달 문제 입니다.
안녕하세요. 이상혁 입니다.

VC로 제작된 DLL의 함수를 LoadLibrary와 GetProcAddress로 호출 하여 사용하려고 합니다.

DLL의 함수 중에 Byte* 를 파라메터로 받아서 결과를 받는 부분이 있습니다.

하지만, 파라메터를 어떻게 전달해야 할지 몰라 진전이 없습니다.

VC++만 사용하다보니 Delphi의 포인터 개념을 몰라서 그런것인지 너무 어렵습니다.

* 아래 함수 중 Open과 Close함수에 대한 호출은 잘됩니다만 ReadInfo와 Apply함수가 문제 입니다.
* ReadInfo의 lpRes대신에 Info (Record)나 PTInfo(Pointer of Record)를 사용하고 싶은게 최종인데,
  여러곳에 찾아보니 배열로 던져서 받은 다음에 메모리 복사 하란 말을 보아서, PByte로 시도 중인 상태입니다.


-- DLL Header파일 --
#define API_DLL __declspec(dllexport)

extern "C" API_DLL unsinged long WINAPI Open(DWORD nPort);
extern "C" API_DLL long WINAPI Close(void);
extern "C" API_DLL unsinged long WINAPI ReadInfo(BYTE *lpRes);
extern "C" API_DLL unsinged long WINAPI Apply(BYTE *ctime, BYTE *indata, BYTE *lpRes);

-- Delphi에 적용한 소스 --

unit unitTest;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TfrmTest = class(TForm)
    function Test( value: Byte ) : Longword;
    procedure Doing();
    procedure FormCreate(Sender: TObject);

  private
    { Private declarations }
  public
    { public declarations }
  end;

  PTInfo = ^Info;
  Info = packed record
    TYPE  : BYTE;
    ALG       : BYTE;
    VK        : BYTE;
    CENTER  : BYTE;
    EP      : array[0..7] of AnsiChar;
    CODE  : BYTE;
    RFU       : array[0..33] of AnsiChar;
  end;

    TDLL_OPEN = function( Port:Longword ) : Longword; Cdecl;
    TDLL_CLOSE = function() : Integer; Cdecl;

    TDLL_READINFO = function( out pInfo: PByte ) : Longword; Cdecl;
    TDLL_APPLY = function( var cTime : pByte; var inData: pByte, out pRes: PByte ) : Longword; Cdecl;

var
    hLibrary : THandle;

    DLL_OPEN                  : TDLL_OPEN;
    DLL_CLOSE                : TDLL_CLOSE;

    DLL_READ_INFO         : TDLL_READ_INFO;
    DLL_APPLY                 : TDLL_APPLY;

implementation

{$R *.drm}

function TfrmTest.Test( value: Byte ) : Longword;
begin
  ShowMessage( 'Value is ' );

  Test := 1;
end;

procedure TfrmTest.FormCreate(Sender: TObject);
var
  pFunction : TFarProc;
begin
  hLibrary := 0;
  hLibrary := LoadLibrary( PChar('Test.dll'));

  if ( 0 = hLibrary ) then
    begin
      showmessage(Test.dll을 찾을 수 없습니다.');
    end
  else
    begin
      { Get 'Open' }
      pFunction := nil;
      pFunction := GetProcAddress( hLibrary, PChar('Open') );
      if ( nil <> pFunction ) then
        begin
          @DLL_OPEN := pFunction;
        end
      else
        showmessage('Open 함수를 찾을 수 없습니다.');

      { Get 'Close' }
      pFunction := nil;
      pFunction := GetProcAddress( hLibrary, PChar('Close) );
      if ( nil <> pFunction ) then
        begin
          @DLL_CLOSE := pFunction;
        end
      else
        showmessage('Close 함수를 찾을 수 없습니다.');


      {Get ReadInfo' }
      pFunction := nil;
      pFunction := GetProcAddress( hLibrary, PChar('ReadInfo') );
      if ( nil <> pFunction ) then
        begin
          @DLL_READINFO := pFunction;
        end
      else
        showmessage('ReadInfo 함수를 찾을 수 없습니다.');


      {Get 'Apply' }
      pFunction := nil;
      pFunction := GetProcAddress( hLibrary, PChar('Apply') );
      if ( nil <> pFunction ) then
        begin
          @DLL_APPLY := pFunction;
        end
      else
        showmessage('Apply 함수를 찾을 수 없습니다.');
  end;

  Doing();

end;

procedure TfrmTest.Doing();
var
  lwReturn : Longword;
  arStream : Byte;
  parStream : PByte;
begin
  if ( nil <> @DLL_READ_INFO ) then
  begin
    arStream := 65;
    parStream := @arStream;

    Test( arStream );
    lwReturn := @DLL_READINFO( parStream );
    if ( 0 = lwReturn ) then
      begin
       ShowMessage( 'Completed?' );
      end
    else
      {ShowResultMessage( lwReturn );}
  end;
end;
end.

-- 끝 --

Test함수는 파라메터를 Byte로 맞추로 부르던, var PByte로 맞추고 부르던 잘되는데요.
@DLL_READINFO는 Byte로 하건 var PByte로 하건 전혀 안됩니다.

'Types of actual and formal var parameters must be identical' 이나
'Variables required' 에러메시지가 사라지지 않습니다.

2일째 이걸로 밤샜습니다 ㅜㅜ

고맙습니다.
2  COMMENTS
  • Profile
    김동원 2007.10.26 00:49
    1. 함수 정의가 문제가 있을듯 합니다.
        TDLL_OPEN = function( Port:Longword ) : Longword; Cdecl;
        TDLL_CLOSE = function() : Integer; Cdecl;

        TDLL_READINFO = function( out pInfo: PByte ) : Longword; Cdecl;
        TDLL_APPLY = function( var cTime : pByte; var inData: pByte, out pRes: PByte ) : Longword; Cdecl;

       위의 함수 정의를 다음과 같이 바꿔줍니다.
       TDLL_OPEN = function( Port:Cardinal) : Cardinal; stdcall;
       TDLL_CLOSE = function() : Integer; stdcall;
      
       TDLL_READINFO = function(Info: Byte) : Cardinal; stdcall;
       --> Info가 단순한 입력인 경우는 위와같이 선언하면 되구요
             Info가 값을 입력하고 다시 돌려받을 용도이면 (var Info : Byte) 이렇게 선언하면 됩니다.

       TDLL_APPLY = function( var cTime : pByte; var inData: pByte, out pRes: PByte ) : Cardinal; stdcall; --> 이 경우의 parameter type은 정확한 설명이 없어서 변경이 어렵습니다. parameter를 정확히 설명해주시면 type 변환이 쉬울듯 합니다.

    2. 함수를 call하는 부분도 문제가 될듯 합니다.
    procedure TfrmTest.Doing();
    var
      lwReturn : Longword;
      arStream : Byte;
      parStream : PByte;
    begin
      if ( nil <> @DLL_READ_INFO ) then
      begin
        arStream := 65;
        parStream := @arStream;

        Test( arStream );

        lwReturn := @DLL_READINFO( parStream ); --> lwReturn := DLL_READINFO(arStream);

        if ( 0 = lwReturn ) then
          begin
           ShowMessage( 'Completed?' );
          end
        else
          {ShowResultMessage( lwReturn );}
      end;
    end;

    위와같이 수정하면 실행될듯 합니다.
    즐푸하세요.

  • Profile
    이상혁 2007.10.26 14:53
    알려주신 방법으로, 해결되었습니다.

    정말 고맙습니다. ^^