C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[808] 실행시 Class XXXX not found. 문제
크레브 [kkol] 8218 읽음    2008-09-25 16:24
classnotfound1.jpg 8.7KB Class xxx not found. 캡쳐
classnotfound2.jpg 27.7KB IDE에서 실행했을때..Class xxx not found.
classnotfound3.jpg 91.1KB IDE에서 실행시 에러 뜨고 디버그 모드 위치
Classnotfound_test.zip 1014.2KB 에러 발생하는 샘플 프로젝트
실행파일을 실행하다보면 다음과 에러가 발생하고서 실행이 안되는 경우가 가끔 발생한다.

Class TComPort not found.


이 글은 해당 문제의 근본적인 원인을 정확히 파악하지는 못했지만
해당 문제가 발생하는 조건 및 옵션 별 테스트를 통해 해당 문제가 발생하지 않도록 하는 방법을
알리고자 하는것이다.

조건 1 : DLL 프로젝트에 TForm을 포함한 리소스가 포함되어 있다.
조건 2 : DLL Form과 그 DLL을 사용하는 프로젝트의 Form에 문제가 되는 같은 콤포넌트가 올라가 있다.
조건 3 : 기본 콤포넌트에 대해서 발생하기 보다는 추가로 설치한 콤포넌트 클래스에서 발생하는 경우가 많다.
조건 4 : dll 임포트 라이브러리(*.lib)를 DLL을 사용하는 프로젝트에 포함한다.
조건 5 : 아래 테이블과 같은 옵션 조건에 따라 발생한다.(프로젝트옵션>Packages > Build with runtime packages)
즉 양쪽다 runtime packages로 작업했을때만 문제가 발생하지 않는다.
  DLL 프로젝트 DLL을 사용하는 프로젝트 결과
Build with runtime packages 옵션 체크 체크 정상(문제없음)
Build with runtime packages 옵션 체크 안함 체크 에러 발생
Build with runtime packages 옵션 체크 체크 안함 에러 발생
Build with runtime packages 옵션 체크 안함 체크 안함 에러 발생


dll에는 TForm 리소스를 포함시키지 않으면 문제가 없을것이다.
하지만 DLL에 Form을 포함시키고 위 문제를 피할 수 있는 방법은 위 테이블에서 네번째 조건인 양쪽 프로젝트 모두 runtime packages 옵션을 꺼두는 방법 밖에 없었다.

또 한가지 해결책은 DLL을 정적로딩(임포트 라이브러리) 하지 않고
api의  LoadLibrary를 사용해서 동적으로 로딩하면 문제를 피해갈 수 있다.
하지만 함수가 많지 않을때는 괜찮지만 함수가 많아질수록 동적 로딩은 사용하기가 부담된다.
사실 함수 하나 마다 다 코딩으로 로딩(GetProcAddress(...)) 하는건 여간 귀찮은 일이 아니다.

[ 동적 로딩 ]
void __fastcall TF_Test::Button4Click(TObject *Sender)
{
   HINSTANCE mInstance;
   AnsiString file = ExtractFilePath( Application->ExeName) + "iPadLink.dll";

   mInstance = LoadLibrary(file.c_str());
   if(mInstance==NULL)
   {
      ShowMessage("iPadLink.dll Loading Fail :" + file);
   }
   else
   {
      ShowMessage("iPadLink.dll Loading OK :" + file);
      // 정상적으로 로딩됨~
   }
}



위의 조건은 완전한 조건이 아니다
알수 없는 조건으로 이런 현상이 생기는 경우도 있었다.
그러므로 DLL에 Form을 포함해서 사용하는 것은 무엇가 알수 없는 찜찜한 문제를 안고 가야만한다.

자신이 직접 만든 DLL이 아니라도
씨++빌더를 이용해서 타 업체에서 만든 DLL 라이브러리( Form을 포함하고있는 )을 사용할때도
가끔 한번씩  우리가 만든 DLL과 알 수 없는 충돌을 일으키는 경우가 꽤 자주 발생한다.
( 프로그램이 실행되다가 죽는다던지 , 그쪽 업체 DLL이 제대로 동작하지 않는다던지 하는 문제)
그때 마다 DLL 로딩 순서 등을 바꿔가며 어떻게든 해결하고 있지만
근본 원인을 알 수 있었던 적은 거의 없다.

[ 정적 LIB 로 링크하면 ]
정적 라이브러리를 만들고 Form을 추가해서 ComPort 콤포넌트를 올렸을 경우에는
위 문제가 발생하지 않는다.
다만 만든 폼의 Form ( *.DFM ) 파일을 사용하는 프로젝트 링크에서 가지고 있어야 한다.


[ BPL 패키지로 만들어 사용 ]
DLL에 폼을 넣어서 만들지 말고 BPL에 넣어서 만들어 보면 괜찮을 듯하다.
BPL은 보통 콤포넌트 패키지를 만들때 사용하는데
여기에 Form 을 추가하여 패키지로 올리면 괜찮을 것 같다.
--> 단점 : bpl로 만드는 파일에는 form 파일이 리소스로 포함되어 있지 않는듯하다. 
사용하는 폼파일(*.dfm)이  bpl을 사용하는 프로젝트 링크시에 연결이 되어야 한다.
즉 사용하는 프로젝트 소스에서 DLL에서 사용하는 폼 파일(*.dfm 파일)들을 가지고 있어야 Build 할 수 있다.


[ 샘플 프로젝트 설명 ]
압축을 풀면
DLL 폴더와 Test 폴더가 있다.
Test 폴더에서 TenkeyTest.exe를 실행하면 해당 메시가 바로 뜬다.
사용 버전 : 씨++빌더 6.0

DLL프로젝트 Form과 사용하는 프로젝트의 Form에 TComPort 가 단순히 올려줘있다.
그 콤포넌트를 이용해 기능을 구현 한 것은 없다.

샘플 소스는 프로젝트 옵션 및 콤포넌트 설치 여부에 따라  Build시 에러가 발생할 수 있다.
빌드를 위해서는 ComPort 콤포넌트가 설치되 있어야 한다.
장성호 [nasilso]   2008-09-25 16:50 X
CPort는 잘 사용하지 않아서  모르겠구요


Build with runtime packages 옵션과 관현하여
Form을 포함한 dll에서는  여러가지 문제가 발생할 가능성이 있습니다.

이 문제로 한때 한참 원인을 찾았는데
임프님께서 설명해주더군요
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_qna&no=50394

원인은 Builder6.0을 기준으로 VCL의  vcl60.bpl  이 dll과 exe 두군데 다  load되기 때문입니다.
그래서 Application 및 Screen  객체들이 싱글톤으로 설계되어있다곤 하지만
실제로는 dll 과 exe에 각각 생성되죠

그래서 exe에 있는 Form에서 참조하는 Application과
Dll에서 참조하는 Application객체가 다른놈이 되어버립니다.


[해결책은]


1. 님께서 말쓴하신대로 Build with runtime packages 옵션을 체크해서 해결할수도 있구요


2. Dll에 Application을 exe에 있는 Application으로 설정

    dll을 loadlibrary한 직후(Form이나 각종 컴포넌트를 생성하기전)에
    exe에 있는 Application 및 Screen객체등을 dll 쪽으로 넘겨서 그쪽에 셋팅해줍니다.

   dll 에서
   void DllAppIni(TApplication *App)
   {
      Application=App;
   }

   그런후에 Form을 생성하거나 Dialog를 쓰거나 하면 괜찮습니다.

그럼..
크레브 [kkol]   2008-09-25 18:55 X
장성호님이 얘기한 2번 방법은 제대로 되지 않습니다.
위에서 얘기한 문제는 따로 DllAppIni() 함수를 호출할 시간도 없이
단지 임포트 라이브러리만 프로젝트에 추가했을때
Form에 같은 콤포넌트가 있으면 해당 FormCreate시에 발생하는 문제입니다.
물론 TComPort 에서만 생기는것은 아니고 제가 다른 콤포넌트에서 발생하는 경우도 있었습니다.
그리고 LoadLibrary를 통한 동적 로딩에서는 발생하지 않는 문제이고요

장성호님의 2번 방법으로 테스트 하면 똑같은 에러메시지가 뜨고
추가로 잘못된 메모리 접근 에러가 한번 더 뜹니다.
테스트 코드는 아래와 같습니다.


__declspec(dllimport) void DllAppIni(TApplication *App);

//---------------------------------------------------------------------------
USEFORM("FTest.cpp", F_Test);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
   DllAppIni(Application);

   try
   {
       Application->Initialize();
       Application->CreateForm(__classid(TF_Test), &F_Test); // Class not found.는 이 부분에서 발생하는 에러임 
       Application->Run();
   }
   catch (Exception &exception)
   {
       Application->ShowException(&exception);
   }
   catch (...)
   {
       try
       {
          throw Exception("");
       }
       catch (Exception &exception)
       {
          Application->ShowException(&exception);
       }
   }
   return 0;
}
//-------

장성호 [nasilso]   2008-09-25 19:18 X
정적으로 Lib로 프로젝트에 포함해서 하는것은 테스트 해본적이 없네요(죄송)
동적으로 DLL LoadLibrary 해서 사용할때 는 저렇게 하면 됩니다만...

정적으로 Lib를  EXE에 vcl60.bpl 이 두개가 들어가게 되는가????

정적으로 할때는 Build with runtime packages 옵션을 체크하는방법 뿐일듯..

시간날때 좀더 연구해 봐야겠습니다.

+ -

관련 글 리스트
808 실행시 Class XXXX not found. 문제 크레브 8218 2008/09/25
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.