죄송합니다.
제가 잘못 답변드렸네요
PACKAGE를 사용해서는 C 스타일로 함수이름 그대로 extern되지 않네요
CBuilder 네임멩글링 규칙에 따라 extern되네요.
PACKAGE 키워드는 동적으로 LoadLibrary + GetProcAddress 로 쓰기엔 맞지 않는것 같습니다.
참고로 CBuilder 네임멩글링 규칙을 보니 ..
1) global변수인경우
변수이름 앞에 언더바('_') 가 붙어서 extern되구요
PACKAGE int iAbc;
"_iAbc" 로 extern됩니다.
2) 함수인경우 이름앞에 꼴뱅이('@')가 붙고 뒤에는 파라메타에 따라 뒤에 다르게 붙습니다.
int MyFunc(); 는 "@MyFunc$qv"
int MyFunc(String s); 는 "@MyFunc$qqr17System@AnsiString"
3) class의 멤버함수인 경우
int myclass::MyFunc(String s) 는 "@myclass@MyFunc$qqr17System@AnsiString"
정확하진 않지만 대충 위와같은 식으로 extern됩니다.
편법이지만
만약 2번 또는 3번과 같이 extern된 경우 앞에 메임멩글링 규칙을 잘 모르니
앞부분의 string만으로 GetProcAddrss 할수도 있습니다.
다음 팁을 쓰면요..
http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=0&st=C&keyword=MyGetProcAddress&indx=402177&keyword1=MyGetProcAddress&keyword2=&page=1
function MyGetProcAddress(hModule : LongWord; pszSymbol : PChar) : Pointer;
type
TWordArr = array [0..0] of Word;
PWordArr = ^TWordArr;
TLongWordArr = array [0..0] of LongWord;
PLongWordArr = ^TLongWordArr;
var
// 각 파일 구조체 선언
pImageBase : PUCHAR;
pImageDosHeader : PIMAGE_DOS_HEADER; // IMAGE_DOS_HEADER
pImageNtHeaders : PIMAGE_NT_HEADERS; // IMAGE_NT_HEADERS
pImageDataDirectory : PIMAGE_DATA_DIRECTORY; // IMAGE_DATA_DIRECTORY
pImageExportDirectory : PIMAGE_EXPORT_DIRECTORY; // IMAGE_EXPORT_DIRECTORY
dwFuncIndex : LongWord;
pFuncName : PChar;
FnIndex: LongWord;
begin
Result := nil;
pImageBase := PUCHAR(hModule);
// 매핑되지 않았다면 종료
// 매핑되지 않았다는 것은 DLL의 주소가 잘못되었다는 것.
if not Assigned(pImageBase) then Exit;
pImageDosHeader := PIMAGE_DOS_HEADER(pImageBase);
// PE 포멧 파일인지 확인하여 PE파일이 아니라면 종료한다.
// PE (Portable Executable) 포멧 파일은 Exe, Dll에 해당한다.
// PE 구조는 IMAGE_DOS_HEADER, IMAGE_FILE_HEADERM, IMAGE_OPTIONAL_HEADER32 헤더로 구성된다.
// IMAGE_DOS_SIGNATURE 0x5A4D (23117 : MZ)
if pImageDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then Exit;
// e_lfanew : PE 헤더의 시작점을 가리키는 RVA 값이다.
// 파일이 매핑된 주소의 시점부터 e_lfanew 값을 더하면 IMAGE_NT_HEADERS 가 나온다.
pImageNtHeaders := PIMAGE_NT_HEADERS(LongInt(pImageBase) + pImageDosHeader.e_lfanew);
// IMAGE_NT_SIGNATURE 를 확인한다.
// IMAGE_NT_HEADERS의 시작지점이 $00004550 값인지 확인한다.
// 0x00004550 (17744 : PE00)
if pImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then Exit;
pImageDataDirectory := @pImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// IMAGE_EXPORT_DIRECTORY : export된 함수들을 담고 있는 구조체이다.
pImageExportDirectory := PIMAGE_EXPORT_DIRECTORY(Cardinal(pImageBase) + pImageDataDirectory.VirtualAddress);
dwFuncIndex := 0;
// pImageExportDirectory.NumberOfFunctions : DLL 파일 내의 export된 함수의 갯수를 의미한다.
// 처음부터 갯수만큼 돌면서 검색하려고 하는 함수가 존재하는 지 확인한다.
while (dwFuncIndex < pImageExportDirectory.NumberOfFunctions - 1) do begin
// 해당 주소의 함수명을 가져온다.
pFuncName := PChar(PLongWordArr(Cardinal(pImageExportDirectory.AddressOfNames) +
Cardinal(pImageBase))^[dwFuncIndex] + Cardinal(pImageBase));
// 검색하려고 하는 pszSymbol 함수와
// DLL에서 검색된 pFuncName 함수를 비교한다.
if StrLIComp(pszSymbol, pFuncName, Length(pszSymbol)) = 0 then begin
// AddressOfNameOrdinals 순서수 테이블
FnIndex := PWORDARR(Cardinal(pImageExportDirectory.AddressOfNameOrdinals) +
Cardinal(pImageBase))^[dwFuncIndex];
// 검색하려는 함수명과 DLL에서 Export된 함수명이 같다면 해당 함수의 주소를 리턴한다.
Result := Pointer(PLongWordArr(Cardinal(pImageExportDirectory.AddressOfFunctions) +
Cardinal(pImageBase))^[FnIndex] + Cardinal(pImageBase));
Break;
end;
// 두 함수가 같지 않으면 Index를 증가해 다음 함수를 검색한다.
inc(dwFuncIndex);
end;
end;
#include "MyLib.hpp"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
typedef void __fastcall ( *MsgFunc)(AnsiString str);
if(OpenDialog1->Execute())
{
HINSTANCE hIns;
hIns=LoadLibraryA(OpenDialog1->FileName.c_str());
if(hIns)
{
//"@ImShowMessage$qqr17System@AnsiString"
MsgFunc func;
func=(MsgFunc)MyGetProcAddress((unsigned int)hIns,"@ImShowMessage$qqr17System@AnsiString");
if(func)
{
func("메세지 잘 되나?");
}
FreeLibrary(hIns);
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
typedef void __fastcall ( *MsgFunc)(AnsiString str);
if(OpenDialog1->Execute())
{
HINSTANCE hIns;
hIns=LoadLibraryA(OpenDialog1->FileName.c_str());
if(hIns)
{
//"@ImShowMessage$qqr17System@AnsiString"
MsgFunc func;
func=(MsgFunc)MyGetProcAddress((unsigned int)hIns,"@ImShowMessage");
if(func)
{
func("메세지 잘 되나?");
}
FreeLibrary(hIns);
}
}
}
주의할점은 비슷한 이름의 함수가 있다면 엉뚱한 놈을 return할수 있습니다.
그럼..
아루스 님이 쓰신 글 :
: PACKAGE 선언 시 동적 로드는 어떻게 해야하나요?
: 외부로 나타난 이름이 함수명 뒤에 () 표시가 들어가있는거 같은데 GetProcAddress 로 안나오네요.
:
:
:
: 장성호 님이 쓰신 글 :
: : 함수나 변수 선언할때
: : 앞에 PACKAGE 라고 쓰면 쉽게 EXPORT됩니다.
: :
: :
: : 아루스 님이 쓰신 글 :
: : : 그냥 일반 DLL 처럼하면 되네요.
: : : export 시에 함수 이름 앞에 underline 들어가는 걸 잊고 원래 함수 이름으로 찾아대니 못찾았던거네요. ㅜㅜ
: : :
: : : 아루스 님이 쓰신 글 :
: : : : 은 무엇일까요. ㅜㅜ
: : : :
: : : : Class 는 등록해서 쓰면 되는데,
: : : : LoadPackage 가 Initialize 함수를 찾아 쓰는 건 알겠는데,
: : : : Initialize 함수 처럼 export 하려는데 모르겠네요.