안녕하세요. 이상혁 입니다.
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일째 이걸로 밤샜습니다 ㅜㅜ
고맙습니다.
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;
위와같이 수정하면 실행될듯 합니다.
즐푸하세요.