unit OptoCom;
interface
type O22_ERROR_CODE = SmallInt;
type O22HCONT = Cardinal;
type PO22HCONT = ^O22HCONT;
type UINT = Cardinal;
const O22_COM_DUDE_HANDLE_INVALID = 0;
const MAX_STRING_SIZE = 255;
function O22MdsSendReceSz(hContArg: O22HCONT;
pCommandArg : Char;
pResponseArg : PChar;
cbRespMaxLen0Arg : UINT ) : O22_ERROR_CODE; stdcall;
implementation
function O22MdsSendReceSz; stdcall; external 'OptoCom.DLL';
end.
여기서 dll 사용을 위하여 interface 와 implememtation 사이에 구현을 했는데
여기다 구현하면 다른 unit에서도 사용할 수 있는것으로 알고 있습니다.
그러면 implementation 밑에 부분은 어떻게 되는 거죠.
실제로 dll의 함수 O22MdsSendReceSz를 사용한다는 선언 부분이것 같은데
이코드도 interface 와 implementation 사이에 들어가야 하는것 아닌가요?
C/C++ 과 비교해서 생각해보면 (잘 모르셔두 상관은 없습니다.)
소스코드에서 실행파일을 생성하는 데 다음과 같은 과정을 거칩니다.
소스코드
|
PreCompile
|
Compile
|
Linking
|
실행 파일
여기서 Compile 과정에서는 실질적인 메모리 주소가 메핑되는 것이 아니라 어디에 있더라 라는 심볼정보가 들어갑니다. Linking 과정에서 정확히 어디~ 라는 것이 매핑되죠.
델파이 PAS 파일의 interface 부분은 C/C++ 의 헤더 파일(*.h)과 관련있고, implementation 부분은 C/C++ 의 소스 파일 (*.c / *.cpp)와 관련 있다고 생각해보면,
interface 부분에서 함수를 선언해주는 것은 다른 유닛에서도 참조할 수 있게 하기 위해서 특성을 타지 않는 것이 좋습니다. 즉, 선언하는 함수가 델파이에서 작성된 전역함수인지 아니면 DLL-exported 함수인지 전혀 관계없다는 것이죠.
implementation 부분은 약간 다른 데, 이 섹션에 들어가는 내용은 위의 생성과정에서 Compile/Linking을 같이 하기 때문입니다. 즉, external 이라는 뜻이 함수의 본체는 현재 정의된 PAS 또는 실행코드 블럭에서 밖에 있다(external 하다, internal 하지 않다)의 뜻으로 해석하시면 될 듯 합니다.
한가지 더,
위에서 interface/implementation 부분을 C/C++ 과 비교 했는 데 정확히 등가는 아닙니다. 위와 같은 경우(DLL-exported 함수를 사용하는 경우)는 interface 부분 역시도 Linking 에 참여하게 됩니다.
예를 들어 comctl32.dll에 들어있는 DllGetVersion 함수를 델파이에서 쓰는 방식은 아래와 같이 3가지나 될 수 있습니다.
DLLVERSIONINFO = record
cbSize :DWORD;
dwMajorVersion :DWORD;
dwMinorVersion :DWORD;
dwBuildNumber :DWORD;
dwPlatformID :DWORD;
end;
PDLLVERSIONINFO = ^DLLVERSIONINFO;
1. interface 부분에 모두 몰아넣는 경우,
interface
...
function DllGetVersion(a_PassedPointer:PDLLVERSIONINFO):HRESULT;stdcall;external 'comctl32.dll' name 'DllGetVersion';
2. interface / implementation에 나누어서 넣는 경우
interface
...
function DllGetVersion(a_PassedPointer:PDLLVERSIONINFO):HRESULT;stdcall;
implementation
...
function DllGetVersion; external 'comctl32.dll' name 'DllGetVersion';
3. implementation 부분에 몰아 넣는 경우
implementation
...
function DllGetVersion(a_PassedPointer:PDLLVERSIONINFO):HRESULT;stdcall;external 'comctl32.dll' name 'DllGetVersion';
이 방식들 중에서 1, 2번만 다른 유닛에서 참조하여 사용할 수 있습니다.
델파이 Windows unit의 경우는 2번의 방식만 사용합니다.
개인적으로는 이런 DLL 사용방식 (보통 static-linking 이라고들 하죠... C++에서 *.lib 파일 사용하는 형식)은 권장하고 싶지 않습니다. 해당 DLL이 없는 경우는 아예 프로그램이 뜨질 않기 때문에... 따라서 개인적으로는 고전적인 LoadLibrary/GetProcAddress/FreeLibrary를 권하고 싶습니다.