2009-10-07 2 views
0

나는 이제 우리는 델파이 2007 에서 우리는 DLL에 대한 C의 ++ 헤더를 가지고 사용하고자하는 등 트럭Delphi에서 "_pascal calling convention"을 사용하여 dll을 호출하는 방법은 무엇입니까?

을 계획하는 데 사용되는 라우팅 프로그램 RouteLogix에서 dll을 RL6_dll.dll 및 작업 예제가 그 C++에서 사용 - Builder. 델파이에서

// Use this routine to find the directory where the data-xxx subdirectories 
// are expected. 
// char * vszBuf - address of a character array to receive the (null-terminated) path. 
// int nBufSize - is the size of the array 
//     (internally we allow paths up to 256 characters long) 

DllFn(void) RL6_GetLocalGeoDir(char *vszBuf, int nBufSize); 

내 시도 :

procedure TfrmRL6Xml.Button1Click(Sender: TObject); 
var 
    s1: PChar; 
    IntValue : Integer; 
    RL6_GetLocalGeoDir: function(vszBuf: pchar; nBufSize: Integer): integer; stdcall; 
begin 
    handle := LoadLibrary('C:\Carp\RL6_app2\rl6dll\RL6_DLL.dll'); 
    if handle <> 0 then 
    begin 
     @DllFn := GetProcAddress(handle, 'RL6_PREINIT'); 
     @RL6_GetLocalGeoDir := GetProcAddress(handle, 'RL6_GETLOCALGEODIR'); 

     s1 := '                                  '; 
     IntValue := length (s1); 
     RL6_GetLocalGeoDir (s1, IntValue); 
     showMessage(s1); 
    end; 
end; 

그래서 지금은 S1이 문자열을 포함하는 기대, 대신 기능을 문자열로있는 intValue을 처리 할 것 같다 여기

해당 파일의 예입니다. s1과 IntValue 매개 변수가 교환 된 것처럼 보입니다. 우리는 물론 RL6_GetLocalGeoDir (IntValue, s1)을 시도했지만 그 중 하나도 작동하지 않았습니다. 그것을 부르는 어떤 제안?

답변

0

당신은 미리 할당 된 버퍼로 프로 시저를 호출해야하고, 올바른 선언, 그래서 같은 :

procedure TfrmRL6Xml.Button1Click(Sender: TObject); 
var 
    s: AnsiString; 
    IntValue : Integer; 
    RL6_GetLocalGeoDir: procedure(vszBuf: PAnsiChar; nBufSize: Integer); stdcall; 
begin 
    handle := LoadLibrary('C:\Carp\RL6_app2\rl6dll\RL6_DLL.dll'); 
    if handle <> 0 then 
    begin 
     @DllFn := GetProcAddress(handle, 'RL6_PREINIT'); 
     @RL6_GetLocalGeoDir := GetProcAddress(handle, 'RL6_GETLOCALGEODIR'); 

     IntValue := 256; 
     SetLength(s, IntValue); 
     RL6_GetLocalGeoDir (PAnsiChar(s), IntValue); 
     s := PAnsiChar(s); 
     showMessage(s); 
    end; 
end; 

편집 :

귀하의 수정 문제는 여전히 나쁜 코드가 포함되어 있습니다. 당신은 당신이 버퍼하지만 코드 세그먼트에서 문자열 상수에 대한 포인터를 제공하지 않는 한 이것은 단지 잘못

var 
    s1: PChar; 

s1 := '                                  '; 
IntValue := length (s1); 

사용합니다. 이것을 사용하는 것은 단지 예를 들어, API 함수 GetWindowsDirectory()로 시도, 충돌로 이어질 것입니다 : ntddll.dll에서 액세스 위반 (예 $0044C6C0에 대한) 코드 영역에있는 주소의 쓰기됩니다이 실행

var 
    P: PAnsiChar; 
begin 
    P := '                    '; 
    GetWindowsDirectory(P, 80); 
end; 

.

+0

나는이 예제를 너무 단순화했습니다. 예제가 바로 수정되었습니다. –

+2

나는 그것이 수정되었다고 생각지 않는다, 왜 당신은'PChar'에'Length()'를 부를까요? – mghie

+0

C에서 "char"은 1 바이트 char이기 때문에 PAnsiChar와 AnsiString을 더 좋게 만듭니다. –

2

퀘스트 제목에는 파스칼 호출 규칙이 언급되어 있지만 질문 본문은 그 주제로 되돌아 오지 않습니다. DLL에 대한 문서에서 파스칼 호출 규칙을 사용한다고 말합니까? 매우 희귀 한 호출 규칙이 요즘 사용됩니다. (Windows API에서 16 비트 일 때 사용되었지만 그 당시의 일부 헤더가 여전히 PASCAL이라고되어 ​​있지만 그 대신 stdcall 호출 규칙을 참조하도록 매크로가 재정의되었습니다.)

DllFn의 정의를 보여 주었다. C 코드도 델파이 코드도 아니다. C에서는 함수의 호출 규칙을 포함하는 매크로라고 상상하므로 실제로 사용되는 것을 확인하기 위해 해당 정의를 찾으십시오. 델파이에서는 함수 포인터로 사용하고있는 것처럼 보입니다. DLL에서 사용하는 것과 동일한 함수 이름을 응용 프로그램에서 사용하는 것이 좋습니다. 모든 사람들이 더 쉽게 생활 할 수있게 해줍니다. 이제는 코드를보고 기능이 실제로 호출되는지 궁금하지 않습니다. 당신은 DLL 정말 파스칼 델파이에서 지정 한 후, 호출 규칙 사용 확인하면

은 함수 선언에에 "파스칼"은 "stdcall을"지시문을 변경하는 것만 큼 간단합니다 :

RL6_GetLocalGeoDir: procedure(vszBuf: PAnsiChar; nBufSize: Integer); pascal; 

나 ' 또한 PChar 인수를 PAnsiChar으로 변경했습니다. 일부 버전의 델파이가 유니 코드이므로 PChar 유형이 PWideChar 일 수 있으므로 여기에 입력하지 않아도됩니다.

관련 문제