C++빌더는 델파이 유닛을 컴파일 할수 있게 컴파일러가 내장되어 있습니다.
즉 *.pas 파일을 프로젝트에 직접 포함해서 하나의 단일한 실행파일을 만들어 낼수 있는 것입니다.
*.pas 를 컴파일 하면 *.hpp 라는 C++용 헤더파일이 생성되며, 이를
#include "*.hpp" 식으로
포함한뒤 델파이로 작성된 유닛의 함수를 호출하거나 변수를 참조해 사용할 수 있습니다.
이런 것은 모두 C++빌더 입장에서 델파이 함수를 호출하는 경우입니다.
그리고 델파이에서 C++로 된 모듈을 붙여 사용하려고 할때는 보통은,
C++로 DLL을 만들어 델파이에서 DLL에 있는 함수를 호출함으로써 기능을 사용하게 됩니다.
이는 델파이로 프로젝트를 진행하는 경우겠지요.
그런데, C++빌더 프로젝트에 *.pas 델파이 유닛을 포함한 경우,
델파이 유닛에서 C++로 플머가 작성한 함수를 호출하고자 할때는 어떻게 하면 될까요?
간단히 생각하고 테스트 해봤는데, 잘 안되 인터넷을 뒤졌는데
헉 생각보다 이런 자료가 없더군요. 아예 전례가 없는 듯이....
그래서 찾기도 귀잖고 해서 직접 실험해서 방법을 알아 냈습니다.
프로그래밍 하다보면 델파이로 코딩하는 경우가 C++로 할때보다 월등히 편리할때가 있습니다.
특히 IE 와 몇가지 COM 관련 제어는 델파이가 더 편리한 경우가 있습니다.
이런 요구는 C++빌더 중 가장 많이 사용되어지는 C++빌더 6의 경우
IE 지원이 조금 취약해 차라리 델파이로 프로그램 하는게 더 편리한데,
문제는 기존 C++로 작성된 부분과 상호 연동이 되어야 하므로,
C++로 작성된 함수를 델파이 유닛에서 호출하려는데 그 방법에 나와 있지 않은 것입니다.
물론 콜백함수를 사용하면 간단히 해결할 수 있지만,
여기서 필자는 일반적으로 다른 유닛에 있는 함수나 DLL에 있는 함수를 사용하듯이
쓰는 방법에 대해 말하고자 합니다.
함수가 여러개 있을때는 콜백함수를 사용하는 것보다 이쪽에 월등히 편리합니다.
우선 델파이에서 호출한 C++ 함수를 작성해야 하는데
델파이는 *.obj 나 *.lib 와 링크 가능하지만 그 속의 명칭이
C 스타일이어야 합니다.
그러므로 함수는 모두
extern "C"
{
// 함수들
int CPP_Proc(int a, int b);
void addmsg(char *msg);
void addint(int v);
};
로 묶여서 외부에 드러내야 합니다.
C++ 유닛이나 폼 소스의
헤더 파일에 위 extern 으로 묶은 함수 리스트의 프로토타입을 써 주고,
cpp 소스 파일에도 extern 으로 묶은 블럭내에 함수의 본체를
코딩 해 주면 됩니다.
이때 주의할 것은 함수 호출규약 __fastcall 을 사용하지 말고
void TestFunc();
처럼 호출 규약을 따로 명시하지 말고 함수를 만들어야 합니다.
이는 델파이 *.pas 쪽에서는 함수가 C에서 사용하던 함수에 대한 링크 기능을 제공하기 때문입니다.
__fastcall를 사용하면 델파이 유닛에서 호출할때 인자 받을때 문제가 생깁니다.
델파이 함수는 모두 디폴트로 __fastcall 을 사용하는데, *.obj 와 링크할때는 예전
C 방식의 링크를 하기 때문에 일어나는 현상입니다.
이렇게 하면 C++빌더쪽 작업은 끝입니다.
다음으로 델파이 *.pas 유닛에서 C++빌더 함수를 호출하게 처리해야 합니다.
interface
구문 밑에 C++로 작성된 함수를 다음의 예와 같이 프로토타입을 맞추어 적어줘야 합니다.
function _CPP_Proc(a:Integer; b:Integer): integer; cdecl; external 'C++Builder6';
procedure _addmsg(msg: string); cdecl; external 'C++Builder6';
procedure _addint(v : integer); cdecl; external 'C++Builder6';
본래 external 'unit1.obj' 처럼 C++ 빌더로 컴파일되어진 C++용 유닛의 obj 명을 적어줘야
원칙이지만 실제 링크할때 전혀 참조하지 않으므로 위와 같이 그냥 적어줘도 됩니다.
특이한 점은 C에서 정의한 함수의 이름과 동일하게 맞추어 주되
앞에 _ 를 붙인다는 점에 유의해야 합니다.
이는 볼랜드 C는 전통적으로 C 함수를 컴파일한 결과의 Obj 파일내에
_ 를 함수나 변수 명칭 앞에 붙이는 것에 기인한 것입니다.
이제 implementation 내에서 C++빌더로 작성한
함수를 마음대로 호출할 수 있게 되었습니다.
다음으로 인자를 넘기는 것에 대해서인데,
위와 같이 표준 C 함수를 부르는 규약인 cdecl; 를 사용함으로써,
인자는 넘기는 순서도 신경쓰지 않아도 됩니다.
다만 델파이에서 빈번히 사용하는 델파이 string을
C++에서 받을때는 char * 형으로 받아서 처리해야 하는데
그 처리하는 방법은 아래와 같습니다.
// 델파이에서는
// ss : string
// ss := '이것은 테스트입니다.';
// _addmsg(ss);
// C++에서는
void addmsg(char *msg)
{
int len = *(int *)(msg - 4);
String s;
s.SetLength(len);
strncpy(s.c_str(), msg, len);
add(s); // 이제 받은 스트링을 AnsiString으로 바꾸어 마음대로 쓸수 있습니다.
}
위 소스는 델파이 스트링 구조를 매우 잘 설명하고 있습니다.
그럼, 보다 자유롭게 델파이 소스와 C++ 소스를 섞어서 사용하시게 되기를...
너무 바쁘게 적어서 문장이 제대로 구성되어 있는지 모르겠습니다. 바빠서 이만.
//---------------------------------------------------------------------------
// 김태성 cppbuilder@naver.com
// 이 강좌는 아무 곳에나 비상업적인 용도에 한해 내용 변경 없이 원래의 출처를 명시하여
// 배포할 수 있습니다. 단, 필자의 이메일로 게제 사실을 통보해야 합니다.
//---------------------------------------------------------------------------
|