본문 바로가기

□컴퓨터 관련/☆C, C++

VC++로 DLL만들기

http://cafe.naver.com/cyberzone/425 

1.정적링크 라이브러리와 동적링크 라이브러리
  - 정적링크 라이브러리: 프로그램에서 호출한 라이브러리의 함수 코드가 실행 파일안으로 복사되어 만들어진다.
  - 동적링크 라이브러리: 실행화일을 만들때 라이브러리에서 사용한 함수에 대한 정보만을 복사하고 함수가 실제 
    실행되는 시점에 라이브러리가 메모리에 로드된다.

2. DLL이란
   실행시에 로드되고 링크 될 수 있는 윈도우즈 프로그램의 기본 모듈이다.

3. DLL의 장점
  - 메모리를 절약할 수 있고 스와핑을 줄일 수 있다.
  - 디스크 용량을 줄일 수 있다.
  - 프로그램 실행속도가 빨라진다.
  - DLL을 업그레이드 하기가 쉽다.
  -여러가지 프로그램언어로 된 응용 프로그램을 지원한다.
  -리소스 교체가 가능하다.
  -프로젝트 관리가 용이하다.

4. DLL의 단점
  -프로그램 배포시 해당 DLL을 함께 배포 해야 한다.

5. MFC와 DLL

  DLL파일(D는 Debug모드)                          기능
=================================== ========================================
 MFC42.DLL( MFC42D.DLL )              기본적인 MFC 클래스들
 MFCO42.DLL( MFCO42D.DLL )            OLE 관련 클래스들
 MFCD42.DLL( MFCD42D.DLL )            ODBC 관련 클래스들
 MFCN42.DLL( MFCN42D.DLL )            네트워크 관련 클래스들
 MSVCRT.DLL( MSVCRTD.DLL )            C run-time library
----------------------------------------------------------------------------

6.MFC를 사용하는 DLL의 종류
 -Regular DLL with MFC statically linked  : 자신이 만든 DLL에 MFC관련 DLL이 포함된다. 다른 응용 프로그램에서 이용가능
 -Regular DLL using shared MFC DLL  : 자신이 만든 DLL에 MFC관련 DLL이 포함되지 않는다.다른 응용 프로그램에서 이용가능
 -MFC Extension DLL using shared MFC DLL : 자신이 만든 DLL에 MFC관련 DLL이 포함되지 않는 DLL로 MFC로 만든
                                                                   응용프로그램에서만 사용가능.

7. 임포트 함수와 엑스포트 함수

임포트함수 :  extern "C"  __declspec(dllimport)   리터형  함수명(매개변수,...) ;
  - 메인프로그램에서 DLL에 있는 함수를 호출할때 사용한다.

엑스포트함수 :  extern "C"  __declspec(dllexport)   리터형  함수명(매개변수,...)
                      {
                             내용;
                      }

  - DLL에서 정의되는 것으로 다른 DLL이나 메인 프로그램에서 가져갈 수 있도록 허용하는 함수이다.


8. 실행화일과 DLL을 연결하는 방법
  1) 암시적 연결
     -실행화일을 생성할때 DLL제공자가 만들어준 임포트 라이브러리를 사용하여 링크한다. 응용프로그램이 로드될때 
      임포트 라이브러리를 참조하여 DLL도 같이 로드된다.
     -DLL과 암시적으로 연결할 때
       * 해당 DLL파일이 있어야 한다.
       * 함수 선언을 해주는 헤더화일이 있어야 한다.
       * 함수정보를 가지고 있는 임포트 라이브러리 화일이 있어야 한다.(*.LIB)

  2) 명시적 연결
     -실행 시간에 직접 DLL을 로드하는 방법이다.
     -DLL을 메모리에 로드하려 할때 윈도우즈는 KERNEL32.DLL 와 USER32.DLL등 미리 인스톨된 DLL에서 다음과 같은 순서로 찾는다.
       * 실행화일이 있는 현 디렉토리
       * Windows\System 디렉토리
       * Windows 디렉토리
       * Path로 지정된 디렉토리
     # 다이알로그를 띄울때는 부모윈도우 포인터를 주어야 합니다.
     예)
       extern "C" __declspec(dllexport)   BOOL ShowLogin( LPSTR user, LPSTR pass)
      {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
 CWnd *pWnd=AfxGetMainWnd();

 CLoginDlg   dlg(pWnd);
 dlg.m_user=user;
 if( dlg.DoModal()==IDOK)
 {
  strcpy(user, dlg.m_user);
  strcpy(pass, dlg.m_pass);
  return TRUE;
 }
 else
  return FALSE;
     }
     


예제)  DLL 프로그램 만들기
 1) MFC AppWizard(DLL)를 이용하여 프로젝트를 생성한다.
 2) 다이알로그 박스등을 만들어 해당 프로그램을 만든다.
 3) 외부에서 참조할 엑스포트 함수를 작성한다.
    extern "C"  _ _declspec(dllexport)
    BOOL ShowLoginDlg(LPSTR userID, LPSTR password)
    {


    }
 4) 엑스포트 함수의 원형을 제공하는 헤더 파일을 작성한다.
    // login.h
    extern "C" _ _declspec(dllimport)
    BOOL ShowLoginDlg(LPSTR userID, LPSTR password);

 5) 컴파일하여 DLL을 생성한다.

 

예제)  실행 화일과 DLL을 연결하는 방법
  1) 암시적 연결
    -DLL화일과 헤더화일(*.h) ,라이브러리 화일(*.LIB)을 가져온다.
    -메인 프로젝트를 생성한다.
    -작업 디렉토리에 헤더화일(*.h)을 복사한다.
    -Debug 폴더에 DLL과 LIB화일을 복사한다.
    -메인 프로그램에 해당 DLL을 호출할 수 있는 프로그램을 작성하고 헤더화일(*.h)을 include 시킨다.

     BOOL CTestApp::InitInstance()
     {
 char user[21]="chang";
 char pass[21];
 if(ShowLoginDialog(user,pass)==TRUE)
 {
   CString str;
          str.Format("user=%s  \n  pass=%s",user,pass);
   AfxMessageBox(str);
 }

 ShowDlg();
     }
    -프로젝트의 Settingsㅇ의 Link탭에서 Object/Library modules 에 import 라이브러리를 지정한다.
     (여러개 지정시 공백으로 구분한다)  예) C:\vc\test\debug\login.lib
     
  2) 명시적 연결
 BOOL CTest1App::InitInstance()
 {
 char user[20]="chang";
 char pass[20];

 BOOL (*pfn)(LPSTR,LPSTR);  //함수포인터

 HINSTANCE hins;
 if((hins=LoadLibrary("changFun.dll"))==NULL)
 {   AfxMessageBox("changFun.dll 화일을 로드할 수 없다");
     return ;
 }
 pfn=(BOOL(*)(LPSTR,LPSTR)) GetProcAddress(hins,"ShowLogin");
 if(pfn==NULL)
 {   AfxMessageBox("ShowLogin function을 로드할 수 없습니다");
     return;
 }
 

 if( pfn(user,pass)==TRUE)
 {
  CString str;
  str.Format("%s   %s",user,pass);
     AfxMessageBox(str);
 }
 else
 {
  AfxMessageBox("접속 불가");
                return FALSE;
 }

 FreeLibrary(hins);

 

 }

  

[클래스 내의 아무 cpp에 추가]

1.로그인 다이얼로그를 만들고 (login.cpp)

2.로긴app에서  외부에서 사용하는 다이얼로그 부르는 함수를 써주고,

#include "LoginDlg.h"

extern "C" __declspec(dllexport) BOOL ShowLogin(LPSTR user, LPSTR pass)
{
 CLoginDlg dlg;
 dlg.m_user = user;
 if (dlg.DoModal() == IDOK) {
  strcpy(user, dlg.m_user);
  strcpy(pass, dlg.m_pass);
  return TRUE;
 }
 else {
  return FALSE;
 }
}

 

2.테스트할 프로젝트를 만들어

. 메뉴에서 로그인 함수 부르는 처리

 

extern "C" __declspec(dllimport) BOOL ShowLogin(LPSTR, LPSTR);

void CDlltest1View::OnLoginDlg() 
{
 // TODO: Add your command handler code here
 char name[20] = "홍길동";
 char pass[20];
 BOOL bCheck = ShowLogin(name,pass);
 if (bCheck) {
  CString str;
  str.Format("사용자: %s \n암  호:%s 님의 접속을 검사합니다.", name,pass);
  MessageBox(str,"접속");
 }
 else {
  MessageBox("접속을 거부합니다.","취소");
 }
}

 

만든 .DLL과 .LIB를 테스트 실행파일이 있는 곳에 COPY후

메뉴 Project-Setting-Link에 Object/Library Module란에  Debug/hsjeon.lib를 써준다.

extern "C" __declspec(dllimport) BOOL ShowLogin(LPSTR, LPSTR);

void CDlltest1View::OnLoginDlg() 
{
 // TODO: Add your command handler code here
 char name[20] = "홍길동";
 char pass[20];
 BOOL bCheck = ShowLogin(name,pass);
 if (bCheck) {
  CString str;
  str.Format("사용자: %s \n암  호:%s 님의 접속을 검사합니다.", name,pass);
  MessageBox(str,"접속");
 }
 else {
  MessageBox("접속을 거부합니다.","취소");
 }
}

 

로그인을 실행하면서 뜨게 하려면 CDlltest1App::InitInstance 에 로긴창을 띄우는 것을

BOOL CDlltest1App::InitInstance()
{
 AfxEnableControlContainer();

 char name[20] = "홍길동";
 char pass[20];
 BOOL bCheck = ShowLogin(name,pass);
 if (bCheck) {
  CString str;
  str.Format("사용자: %s \n암  호:%s 님의 접속을 검사합니다.", name,pass);
  MessageBox(str,"접속");
 }
 else {
  MessageBox("접속을 거부합니다.","취소");
  return FALSE;
 }

선언을 cpp마다 하기가 .. 그래서 .H로 만들어 INCLUDE 해서 사용할 수 있다.

extern "C" __declspec(dllimport) void ShowCal();
extern "C" __declspec(dllimport) BOOL ShowLogin(LPSTR, LPSTR);

 

 

int a;

int *p;

p = &a;

 

k = aa(10,5);

int (*)q;   //함수포인터

 

q = aa;

k = q(10,5);

 

 

[명시적dll연결]

void CDlltest2View::OnLoginDlg() 
{
 // TODO: Add your command handler code here
 // TODO: Add your command handler code here
 HINSTANCE hinst = LoadLibrary("hsjeon.dll");
 if (hinst == NULL) {
  AfxMessageBox("hsjeon.dll이 없습니다.");
  return;
 }
 BOOL (*pFn)(LPSTR, LPSTR);
 pFn = (BOOL (*)(LPSTR,LPSTR))GetProcAddress(hinst,"ShowLogin");
 if (pFn == NULL) {
  AfxMessageBox("ShowLogin함수가 없습니다.");

  FreeLibrary(hinst);
  return;
 }
 char name[20] = "홍길동";
 char pass[20];

 BOOL bCheck = pFn(name,pass);
 if (bCheck) {
  CString str;
  str.Format("이름:%s 암호:%s 님이 로그온 했습니다.", name,pass);
  AfxMessageBox(str);
 }
 else {
  AfxMessageBox("로그온 할 수 없습니다.");
 }
 FreeLibrary(hinst);

}

 

 

void CDlltest2View::OnCalDlg() 
{
 HINSTANCE hinst = LoadLibrary("hsjeon.dll");
 if (hinst == NULL) {
  AfxMessageBox("hsjeon.dll이 없습니다.");
  return;
 }

 void (*pFunct)();

 pFunct = (void (*)())GetProcAddress(hinst, "ShowCal");
 if (pFunct == NULL) {
  AfxMessageBox("ShowCal함수가 없습니다.");
  FreeLibrary(hinst);
  return;
 }
 pFunct();
 FreeLibrary(hinst);

}

 

dll만들때 shared로 하려면

 AFX_MANAGE_STATE(AfxGetStaticModuleState());을 넣어준다. 

 그리고 dlg 인스턴스화 할때

 CWnd *pWnd=AfxGetMainWnd();를  준다.

 CLoginDlg dlg(pWnd);

 

extern "C" __declspec(dllexport) BOOL ShowLogin(LPSTR user, LPSTR pass)
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 CWnd *pWnd=AfxGetMainWnd();
 CLoginDlg dlg(pWnd);
;
 dlg.m_user = user;

...

}


#include

 

int division(int x, int y);          

 

void main()
{

//int division();


int (*ptr_int)(int x1, int y1);     //함수포인터 선언시.. 매개변수가 빠졌네요..


int a=300, b=30, value=0;

 

ptr_int = division;

 

value= (*ptr_int)(a, b);

 

printf("%d / %d = %d",a,b,value);
}

 

int division(int x,int y)
{
return(x/y);
}

'□컴퓨터 관련 > ☆C, C++' 카테고리의 다른 글

[Batch] 해당 폴더 내 특정 파일 검색하기  (2) 2016.11.17
GetLastError() Return Value [펌]  (0) 2011.02.23
warning c4996 strcpy deprecated  (0) 2011.02.11
#pragma란?  (2) 2010.04.07
데브피아  (3) 2010.02.08
매트랩 기본  (0) 2008.10.07
비트연산  (0) 2008.10.02