http://goo.gl/YsesDP




우선 dll 을 만들어 컴파일 하면, 프로젝트명과 동일한 헤더파일, lib 파일, dll 파일이 

생성이 생성되는데...


묵시적으로 dll 을 로드할 경우 위 3개의 파일이 모두 필요 합니다.
(헤더파일이 없어도 되지만, 왜? 헤더까지 필요한지는 아래에 추가로 언급)

dll 의 헤더파일 : 컴파일 할 때 dll 에 있는 함수의 원형을 알아야 한다.
                        -> dll 의 헤더파일이 필요한 이유는 조금 아래에 설명~
dll 의 lib 파일: 링크 시킬 때, dll 에 있는 함수의 몸체(정의부) 를 연결 시켜 실행파일 생성시 필요
                     -> 프로젝트 속성 또는 #pragma comment(lib,,,,) 에서 lib 링크 처리 필요~
dll 파일 : exe 파일이 실행 될 때, dll 에 있는 함수를 호출할 때 필요

->  이 중, 헤더파일, lib 파일은 사용하려는 곳의 소스파일이 있는 폴더에 복사를 시켜두고,
      dll 파일은 exe 실행파일이 있는 곳에 복사를 해 둡니다.


아마. dll 의 헤더파일이 왜?? 필요한가?? 궁금할 텐데...질문한 코드에 보면 묵시적으로 dll 의 함수를
로드할 때,,,

extern "C" __declspec(dllimport) int my_add(int a,int b); 라는 부분이 보입니다.

만약, dll 에서 로드할 함수의 수가 굉장히 많다면, 저 함수들을 사용하는 곳에서 저렇게 일일이 함수 원형 선언을 해주는 것은 노가다 행동일 뿐이죠~

즉, dll 의 헤더파일을 사용하려는 곳에도 복사해주는 이유는 이런 불편함을 줄이기 위함 입니다.

고로, 헤더파일과 cpp 파일을 다음과 같이 수정해 줍니다.

- my_Math.h -

#pragma once

#ifdef DLLEXPORT  // DLLEXPORT 상수가 선언되어 있다면...
#define DLLTYPE __declspec(dllexport)
#else  // 그렇지 않다면...
#define DLLTYPE __declspec(dllimport)
#endif 

extern "C"  DLLTYPE int my_add (int a, int b);

...이하 동일


- my_Math.cpp -


#define  DLLEXPORT  // DLLEXPORT 상수선언 (export  될 것임을 명시하는 부분)

#include "my_Math.h"


extern "C"  DLLTYPE 
int my_add (int a, int b)
{
 .......
}

...이하 동일...



명시적으로 로드할 경우는 위 3개 파일 중에서 dll 파일 하나만 있으면 됩니다.
이 경우, dll 파일 역시, exe 파일이 있는 곳의 폴더에 복사를 해두면 되겠습니다.

일단,,,dll 프로젝트를 빌드하여 lib 파일 dll 파일이 제대로 생성되는지를 본인이 확인해야 합니다.

__declspec(...)  <-- 이 문법에서도 언더바 __ 가 2개 인 것도 확인 하시고...

dll 프로젝트를 빌드하여 제대로 lib, h파일, dll 파일이 생성되었으면 일단 dll 을 사용할 준비가
된 겁니다.

이 생성된 파일들을 위에서 언급한 곳으로 각각 이동을 시킵니다.


- 명시적 실행 소스 코드 -


#include <stdio.h>
#include <windows.h>


// 명시적으로 로드하는 경우, dll 에서 직접 함수의 주소를 읽어 오므로

// 함수의 원형선언 조차도 필요 없습니다.

//_declspec(dllimport) int my_sub(int,int);
//_declspec(dllimport) int my_add(int,int);


typedef int (*ALUFunc)(int,int);


int main()
{
   int a=3,b=5;
   int result;

 ALUFunc my_func ;  //함수 포인터 선언

 HINSTANCE hInstLib = LoadLibrary("___.dll");  // dll 파일명 맞는지 확인할 것 !!

 if (hInstLib == NULL)
{
     printf("오류: DLL을 불러올 수 없습니다\n");
                return 1;
 }
    my_func = (ALUFunc)GetProcAddress(hInstLib,"my_add");

   if (my_func==NULL)
   {
      printf("오류: DLL 함수를 찾을 수 없습니다\n");
                FreeLibrary(hInstLib);
                return 1;

   }

        // 함수 요청하기.
        result = my_func(1, 2);
 
        // DLL 파일의 로드를 해제한다
        FreeLibrary(hInstLib);
 
        // 결과를 보여 준다
        printf("결과는: %f\n", result);

}


=> 특별히 잘못된 부분은 없어 보입니다. LoadLibrary 함수 호출시 dll 파일명이 제대로 되어 있는지
     다시한번 체크를 하는게 좋겠습니다.


- 묵시적 실행 소스 코드 -


#include <stdio.h>

#include "my_Math.h" // dll 의 헤더 포함


#pragma comment(lib, "my_Math.lib")  // 필요한 함수가 어떤 dll 에 있는지 알려주는 역할(링크시 필요)


// dll 의 함수의 원형을 이렇게 하나씩 선언해도 되긴 하지만, 함수의 수가 많아지면

// 이는 굉장히 귀찮은 작업이 됩니다. (my_Math.h 포함하는 것으로 이를 방지함)

/*

extern "C" __declspec(dllimport) int my_add(int a,int b);
extern "C" __declspec(dllimport) int my_sub(int a,int b);
extern "C" __declspec(dllimport) int my_mul(int a,int b);
extern "C" __declspec(dllimport) int my_div(int a,int b);

*/


int main()
{
   int a=3,b=5;

 printf("%d",my_add (a,b));

// return a+b;
 printf("%d",my_sub (a,b));

// return a+b;
 my_mul (a,b);

// return a+b;
my_div (a,b);

 return 0;
}



반응형
http://ha2rupms.tistory.com/79

[Lib] 정적 라이브러리 만들기

프로그래밍/Library 2012/10/05 22:03


정적 라이브러리 프로젝트 만드는 법


아주 기초부터 해볼께요 !





우선 Win32 프로젝트로 원하는 폴더에 이름을 생성한 후 프로젝트를 만듭니다.

확인을 누르시구요,






여기서 정적 라이브러리를 선택한 후, 미리 컴파일된 헤더는 선택 하셔도, 안하셔도 됩니당.

저는 선택 하는 것으로 할게요 /ㅅ /





여기서 Lib 프로젝트의 속성을 지정해주기 전에 해당 폴더 내에 Include 폴더를 생성합니다.

이 Include 폴더 안엔 라이브러리 화! 할 헤더를 담아 놓습니다. 위의 폴더를 예로들면 cMsLib.h 가 되겠네요^^






자, 기본 설정을 했으니 이제 속성 설정을 해볼게요.


프로젝트에 속성을 여시구요.



C/C++ -> 일반 -> 추가 포함 디렉터리에 방금 만든 Include; 를 넣습니다.


추가 포함 디렉터리란 말 그대로 추가적으로 포함할 디렉터리를 말하고, 그 폴더 내의 파일을 사용할 수 있게 합니다.


폴더의 구분은 ' ; ' 로 합니다.



디렉터리를 추가 하셨으면, 





라이브러리 관리자 -> 일반에서 


(ProjectName).lib 를 (ProjectName)_d.lib 로 바꿔주세요. 이는 Release 모드 시의 Lib와 Debug 모드 시의 Lib를 구분하기 위함입니다.



참고로 말씀드리자면, Release 모드에서도 Lib 사용하고자 원하시면, Debug 모드의 출력 파일명을 변경하는 것을 제외하고는 

Release 모드에서도 똑같이 변경 하셔야 해요. 위에서 한 것과 앞으로 할 일두요 !! 






자, 이제 Lib 파일만 편하게 가져다 쓸 수 있게 폴더들을 미리 만들어 볼게요.


Lib 프로젝트 상위에 Lib 폴더를 만드시고, 그 아래에 Include와 Lib 폴더를 또 각각 만들어주세요.





그리고 빌드 이벤트 -> 빌드 후 이벤트 -> 명령 줄에 명령어를 써 넣어 봅시다 !


위의 이상한 copy copy copy 3 줄은 

"~~~~" 에 있는 lib를 "~~~~"로 복사한다 ! 라는 뜻입니다.


즉, 현 위치에 있는 .lib 와 .pdb 파일은

위에서 만들어 놓았던 ../ 상위의 Lib 폴더의 Lib 폴더 안에 복사한다는 말 이구요 ~


Include 폴더 안에 있는 .h 파일을 ../ 상위의 Lib 폴더의 Include 폴더 안에 복사한다는 말 입니다.



이렇게 해 놓으면 나중에 Lib 폴더 하나만 가져가도 라이브러리를 쓸 수 있게 되니 아주 편리합니다.






자, 이제 Lib 프로젝트에서 할 수 있는 것은 다 했어요 !! (아마, 제가 아는 선에서는 말이죠 ... )


그렇다면 이제, 프로젝트 종속성을 바꿔줍니당.



Lib 프로젝트에서 빌드를 다 하고 난 후에 그 Lib를 사용하는 프로젝트 (위에서는 121005_Lib 연습 프로젝트) 를 빌드 해야겠지요?


때문에 종속성이 필요한 것입니다.



위처럼 종속성을 클릭하면,




이와같은 창이 나타납니다. 우선 빌드할 Lib 프로젝트를 선택하시면 되요~





그리고, Lib 프로젝트가 아닌 프로젝트를 시작 프로젝트로 설정하면 끄~읕 입니다^_^


반응형

'운영체제 & 병렬처리 > DLL_LIB' 카테고리의 다른 글

DLL 명시적, 묵시적 호출방법  (0) 2013.09.12
DLL 임포트 방법들  (0) 2012.11.20
DLL 제작방법 – 1. Non-MFC DLL  (0) 2012.11.03
directx 릴리즈,디버그 lib  (0) 2012.11.02
lib 파일 생성과 사용  (0) 2012.11.01
http://idroid.tistory.com/19

1) Visual Studio의 속성페이지에서 링커-입력-추가종속성에서 관련 lib를 추가한다.

2) 소스에서 다음과 같은 지정문을 작성한다

      #pragma comment(lib, "libName.lib")

3) 프로젝트에 임포트 라이브러리를 추가한다. (솔루션 탐색기-프로젝트 우클릭-추가-기존 항목-임포트 라이브러리 선택)



반응형

http://rainiac.com/dev/index.php/dll-%EC%A0%9C%EC%9E%91%EB%B0%A9%EB%B2%95-1-non-mfc-dll/


DLL 제작방법 – 1. Non-MFC DLL

1.1Basis

 

1.1.1Features

  • 내부적으로 C++ 클래스를 사용할 수 있고, C 함수 Wrapper만을 Export 할 수 있다. 따라서 내부적인 C++ Class에 대한 변경은 DLL의 호출에 영향을 주지 않는다.
  • MFC를 사용할 수 없으며, 별도의 MFC Library가 필요없다.
  • DLL을 사용하는 Client는 DLL 호출을 지원하는 어떠한 Language로 작성될 수 있다.
  • AppWizard를 이용하여 자동으로 Project를 생성할 수 있다.

 

1.1.2 Function Export

DLL 내에서 정의된 Function을 export하기 위해서는 “__declspec(dllexport)” 를 사용한다. “__declspec”은 MS만의 C, C++의 확장된 syntax로서, 확장된 storage-class 정보를 정의한다. “dllexport”는 storage-class의 한 속성으로, DLL의 Function, Data, Object를 export할 수 있도록 하여준다. 반대로 DLL내의 Function을 import하기 위해서는 “dllimport” 속성을 사용한다. Win32 환경에서는 Function Export/Import를 위하여 이것을 이용하며, Win32 이전의 Windows 환경에서 사용되던 module-definition file (.DEF)을 사용하지 않는다. 단, .Net 이전의 VB 등의 툴과 호환가능한 DLL을 제작하는 경우, module-definition file을 사용하도록 한다.

 

· export / import

함수 export/import를 위하여 아래와 같이 함수를 선언한다. Coding의 편의를 위하여 export선언을 #define으로 간략화시킨다.

#define DLLImport  __declspec(dllimport)
#define DLLExport  __declspec(dllexport)

DLLExport void somefunc();

· export/import Tips

위 방법으로 export/import 함수를 정의하면, DLL 내에서의 함수 정의와 DLL을 사용하는 Client에서의 함수정의를 다르게 해야 하는 불편이 생긴다. DLL과 Client에서 동일한 Header File을 사용할 수 있도록 하기 위하여 아래와 같이 export/import 함수를 정의한다.

#ifdef DLLTEST_EXPORTS
    #define DLLFunction  __declspec(dllexport)
#elseif 
    #define DLLFunction  __declspec(dllimport)
#endif

DLLFunction void somefunc();

“DLLTEST3_EXPORTS” 은 DLL의 Project Settings에 Preprocessor definitions에 “프로젝트명_EXPORTS”의 형식으로 정의 되어 있다. 따라서 DLL Project에서는 export로, Client Project에서는 import로 동작한다.

 

· Adjusting Naming Convention

C++은 C와 다른 Naming Convention을 사용한다. 따라서 export되는 함수명은 Compile시에 기존의 정의한 이름과 다르게 해석된다. 따라서 Naming Convention에 대한 조정과정이 없으면, export된 함수는 C++ 이외의 Language로 작성되는 프로그램에서는 호출될 수 없다. extern “C”는 함수가 C naming convention을 사용하도록 만들어주며, 이를 통하여 C++로 작성되어 export되는 함수를 다른 Language에서도 사용가능하도록 하여 준다. VC는 기본적으로 프로젝트생성시에 C++을 사용하도록 구성되므로 모든 export함수는 Naming Convention의 조정이 필요하다.

#ifdef _USRDLL
    #define DLLFunction  __declspec(dllexport)
#elseif 
    #define DLLFunction  __declspec(dllimport)
#endif

#ifdef __cplusplus
extern “C” {
#endif

DLLFunction void somefunc();

#ifdef __cplusplus
}
#endif

· Adjusting Calling Convention

이전의 Visual Basic과 같은 C 이외의 다른 언어는 C와 다른 Calling Convention을 사용하므로 다른언어에서 사용될 DLL을 작성하는 경우, 이를 조정해주어야 한다. VC는 기본적으로 “__cdecl” 방식을 사용하며, 다른 언어는 표준방식인 “__stdcall” 방식을 사용한다. 따라서 Project 속성페이지에서 “구성속성 – C/C++” 페이지의 “고급” 항목을 선택하여 “호출 규칙”을 “__stdcall”로 설정한다.

image

 

속성을 사용하지 않고 코드내에서 직접 지정하고 싶다면 아래와 같이 함수 선언과 구현시 함수명 앞에 Calling Convention을 지정해 준다.

 

DLLFunction void __stdcall somefunc();

DLLFunction void __stdcall someFunc()

{

}

 

 

만약 DLL을 .Net 이전의 Visual Basic 과 같은 언어에서 사용하고자 한다면, module-definition file(.Def)을 작성하여 프로젝트에 포함시킨다. VC로 작성한 DLL을 예전의 Visual Basic에서 사용하는 경우, Calling Convention이 다르다는 에러를 자주 볼 수 있는데, 이는 모두 Calling Convention을 조정과정을 거치지 않아서 발생하는 문제이다.

 

Win32DLLSample.def

LIBRARY                   "Win32DLLSample.DLL"

 

EXPORTS

   somefunc   @1

 

1.2 Making DLL

1.2.1 목표

간단한 DLL을 만들기 위하여 아래와 같은 두가지의 기능만을 가지는 DLL을 만들기로 한다.

 

  • int 형의 두 숫자를 parameter로 받아 그 합을 return하는 함수
  • 두개의 string을 받아 연결된 string을 넘겨주고, 그 총 길이를 return하는 함수

 

1.2.2 구현방법

  • 새 프로젝트를 선택한 후, 프로젝트 유형을 아래와 같이 Visual C++ 카테고리의 “Win32 프로젝트”로 선택한다.

image

 

  • 용 프로그램 마법사에서 아래와 같이 “DLL”을 선택 후, 마침을 클릭하여 프로젝트를 생성한다.

image

 

  • export할 함수의 정의를 위하여 Header File을 생성한다. 이는 후에 import 측에서도 공용으로 사용될 것이다. “SimpleDll.h”의 이름으로 Header를 생성하고, 두개의 함수를 위한 함수정의를 만든다.

[Win32DLLSample.h]

#pragma once
 
#ifdef WIN32DLLSAMPLE_EXPORTS
   #define DLLFunction __declspec(dllexport)
#else
   #define DLLFunction __declspec(dllimport)

#endif
 
extern "C" {
 
DLLFunction int __stdcall addint(int n1, int n2);
DLLFunction int __stdcall addchar(char* s1, char* s2, char* added);
 
}

  • 선언한 함수에 대하여 기능을 작성한다. 두 함수는 단지 int형과 char형의 더하기 만을 지원하므로 아래와 같이 함수를 작성한다.

[Win32DLLSample.cpp]

#include "stdafx.h"
#include "stdio.h"
#include "Win32DLLSample.h"
 
DLLFunction int __stdcall addint(int n1, int n2)
{
   return n1 + n2;
}
 
DLLFunction int __stdcall addchar(char* s1, char* s2, char* added)
{
   sprintf(added, "%s%s", s1, s2);
   return strlen(added);
}

  • 여기까지 작성하였다면 컴파일하여 Lib 파일과 DLL 파일을 얻을 수 있다.

 

1.3 Using DLL

앞에서 작성한 코드를 컴파일하여 Win32DLLSample.dll 파일을 얻는다. 이것을 테스트하기 위하여 VC++ 및 VC#에서 DLL내의 함수를 호출하는 기능을 작성한다.

 

1.3.1 Using DLL with Visual C++ (Link Implicitly)

Dialog-Based 프로젝트를 생성하여 아래와 같은 순서로 DLL의 함수를 호출하는 기능을 작성한다.

 

  • 앞에서 작성한 “Win32DLLSample.h”를 프로젝트에 추가한다.
  • 프로젝트 속성페이지에서 “구성속성 – 링커 – 입력”을 선택한 후, “추가종속성” 항목에 “Win32DLLSample.lib”를 추가한다. “Win32DLLSample.lib” 파일은 VC++의 환경설정의 Directories에 존재하는 폴더 또는 Project 폴더에 복사하도록 하거나 “구성속성 – VC++ 디렉터리”를 선택하여 “라이브러리 디렉터리” 항목에 Lib 파일이 존재하는 폴더를 추가한다.

image

 

  • Dialog를 다음과 같이 만들고 각 컨트롤에 멤버변수를 추가한다.

image

  • DLL 함수를 호출할 Button에 대한 Handler를 작성한다.

[Win32DLLSampleTestDlg.cpp]

#include "Win32DLLSample.h"void CWin32DLLSampleTestDlg::OnBnClickedButtonInt()
{
   UpdateData(TRUE);
   m_nIntSum = addint(m_nInt1, m_nInt2);
   UpdateData(FALSE);
}
 
 
void CWin32DLLSampleTestDlg::OnBnClickedButtonChar()
{
   char s1[9];
   char s2[9];
   char sSum[17];
 
   UpdateData(TRUE);
 
   lstrcpy(s1, (LPCTSTR)m_sChar1);
   lstrcpy(s2, (LPCTSTR)m_sChar2);
 
   addchar(s1, s2, sSum);
 
   m_sCharSum = sSum;
   UpdateData(FALSE);
}

위의 방법으로 DLL 함수를 호출하는 프로그램을 작성하여 실행하면 각 함수들이 정확하게 호출되고 있음을 확인할 수 있다.

 

1.3.2 Using DLL with VC++ (Link Explicitly)

Explicit Link를 사용하여 DLL 함수를 호출하는 경우, Header 파일과 Library 파일은 필요하지 않다. 단지 그 함수의 원형만을 알고 있으면 된다. Explicit Link를 사용하기 위하여 아래와 같은 순서로 DLL 함수를 호출하는 기능을 작성한다.

 

  • 1.3.1에서와 같이 Dialog-Based 프로젝트를 생성한 후, 같은 모양으로 Dialog를 만들고 멤버변수를 연결한다.

 

  • DLL 함수호출을 위한 Button의 Handler를 만들고 아래와 같이 코드를 작성한다.

[SimpleDllTest2.Dlg.cpp]

void CSimpleDllTest2Dlg::OnAddint() 
{
   int (*lpfnAddInt)(int, int);
   HINSTANCE hLib = LoadLibrary("Win32DLLSample.dll");
   if(hLib == NULL)
                 return;

   lpfnAddInt = (int(*)(int, int))GetProcAddress(hLib, "addint");
   if(lpfnAddInt == NULL)
   {
                 FreeLibrary(hLib);
                 return;
   }

   UpdateData(TRUE);
   m_nSumInt = lpfnAddInt(m_nInt1, m_nInt2);
   UpdateData(FALSE);

   FreeLibrary(hLib);
}

위와 같이 LoadLibrary를 이용하여 Explicit Link로 DLL 함수를 호출하도록 하면, 별도의 Library와 Header가 필요하지 않으며, 실행 시간에 DLL의 Load와 Unload의 시점을 결정할 수 있는 장점이 있다.

 

1.3.3 Using DLL with C#

C#에서는 DLL의 함수 호출이 매우 간단하다. 단지 어떤 Library의 어떤 함수를 사용할 것인지에 대한 선언만 정확이 명시하면 된다. 아래와 같이 “addint” 와 “addchar” 함수를 선언한다.

C#은 Calling Convention 등을 모두 속성으로 설정 가능하므로, 대부분의 DLL을 그대로 호출할 수 있다.

[DllImport("Win32DLLSample.dll")]
public static extern int addint(int n1, int n2);
[DllImport("Win32DLLSample.dll")]
public static extern int addchar(string s1, string s2, StringBuilder sum);

함수선언 후, 실행을 위한 Handler에서 아래와 같이 호출한다.

private void btnInt_Click(object sender, EventArgs e)
{
   int n1, n2;
   n1 = int.Parse(txtN1.Text);
   n2 = int.Parse(txtN2.Text);

   int sum = addint(n1, n2);
   txtNSum.Text = sum.ToString();
}

private void btnString_Click(object sender, EventArgs e)
{
   var sb = new StringBuilder(100);
   addchar(txtS1.Text, txtS2.Text, sb);
   txtSSum.Text = sb.ToString();
}

위에서 사용된 DllImport Attribute는 몇가지 옵션필드를 가질 수 있다. 이 필드 중 주요한 항목은 아래와 같다. 자세한 내용은 DllImportAttribute Class를 참조한다.

필드

설명

Calling Convention

DLL 내의 Export 함수에 대한 Calling Convention을 지정할 수 있다.

Cdecl, Winapi, StdCall 을 지원하며, 기본값은 StdCall 이다.

CharSet

문자열에 사용할 Character Set을 설정한다.

None(자동), Unicode 값을 가질 수 있다.

Entry Point

DLL 내의 함수가 호출되는 이름을 나타낸다.

이를 이용하면 함수진입점을 지정하여, 선언시 다른 이름으로 별칭을 이용할 수도 있다.

 

아래는 DllImport Attribute를 사용하여 함수에 별칭을 부여한 예이다.

[DllImport(“user32”, CharSet = CharSet.UniCode, EntryPoint = “MessageBoxW”)]
public static extern int MsgBox(int hWnd, String pText, String pCaption, int uType);

Unmanaged Code의 Data Type은 C#(Managed Code)에서 아래와 같이 변환한다.

C (Unmanaged Code)

C# (Managed Code)

HANDLE, void* 또는 일반 pointer

IntPtr

BYTE, unsigned char

Byte

short

Short

WORD, unsigned short

Ushort

int

int

UINT, unsigned int

uint

long

int

BOOL, long

int

DWORD, unsigned long

uint

char

char

LPSTR, char*

string 또는 StringBuilder

LPCSTR, const char*

string 또는 StringBuilder

BSTR

string

float

float

double

double

HRESULT

int

VARIANT

object

 

반응형

릴리즈모드 사용 라이브러리 
dxguid.lib 
dxerr9.lib 
d3d9.lib 
d3dx9.lib 
version.lib 
winmm.lib 
comctl32.lib

 

디버그모드 사용 라이브러리 
dxguid.lib 
dxerr9.lib 
d3d9.lib 
d3dx9d.lib   , sdk 에 따라 d3dx9dt.lib 일 수 있음
winmm.lib 
version.lib 
comctl32.lib

반응형

 

lib 파일 만든후 lib 링크 하고

lib파일과, 헤더파일 해당 프로젝트에 복사 한 후

헤더파일을 include 하면 함수를 사용 할 수 있다.

 

 

우선 해당 lib파일을 project에 include 시켜주어야 합니다.

그방식은 project->Setting->Link탭에서 library modules에 포함시키시거나

 

아래와 같이 Header파일에 포함하는 방식이 있습니다.

#pragma comment(lib, "C:\\abc\abc.lib")

 

다음으로 PcmtoWave()함수가 선언된 Header파일을 님이 사용하시려는 곳에서 include 시켜주시고

 

PcmtoWave()를 호출하시면 됩니다.

 

첫번째 Parameter는 PCM파일의 Path를 집어넣으시면 되고, 두번째 Parameter에서는 변환되서 저장될

 

Wav파일의 Path를 넘겨주시면 될듯 하네요






 http://pmguda.com/52


 라이브러리란?

특정한 코드(함수 혹은 클래스)를 포함하고 있는 컴파일된 파일이다. 

라이브러리를 만드는 이유?
 자주 사용되는 특정한 기능을 main 함수에서 분리시켜 놓음으로써, 프로그램을 유지, 디버깅을 쉽게하고 컴파일 시간을 좀더 빠르게 할수 있기 때문이다.

라이브러리에도 그 쓰임새에 따라서 여러가지 종류가 있다(크게 3가지). 가장 흔하게 쓰일수 있는 "정적라이브러리"와 "공유라이브러리", "동적라이브러리" 가 있다.

이들 라이브러리가 서로 구분되어지는 특징은 적재 시간이 될것이다.

정적라이브러리

정적라이브러리는 object file(.o로 끝나는) 의 단순한 모음이다. 정적라이브러린느 보통 .a 의 확장자를 가진다. 간단히 사용할수 있다. 컴파일시 적재되므로 유연성이 떨어진다. 최근에는 정적라이브러리는 지양되고 있는 추세이다. 컴파일시 적재되므로 아무래도 바이너리크기가 약간 커지는 문제가 있을것이다.

공유라이브러리

공유라이브러리는 프로그램이 시작될때 적재된다. 만약 하나의 프로그램이 실행되어서 공유라이브러리를 사용했다면, 그뒤에 공유라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유라이브러리를 사용하게 된다. 그럼으로써 우리는 좀더 유연한 프로그램을 만들수 잇게 된다.

정적라이브러리와 달리 라이브러리가 컴파일시 적재되지 않으므로 프로그램의 사이즈 자체는 작아지지만 이론상으로 봤을때, 라이브러리를 적재하는 시간이 필요할것이므로 정적라이브러리를 사용한 프로그램보다는 1-5% 정도 느려질수 있다. 하지만 보통은 이러한 느림을 느낄수는 없을것이다.

동적라이브러리

공유라이브러리가 프로그램이 시작될때 적재되는 반면 이것은 프로그램시작중 특정한때에 적재되는 라이브러리이다. 플러그인 모듈등을 구현할때 적합하다. 설정파일등에 읽어들인 라이브러리를 등록시키고 원하는 라이브러리를 실행시키게 하는등의 매우 유연하게 작동하는 프로그램을 만들고자 할때 유용하다.

– MS VC++  라이브러리 만들기


사용자 삽입 이미지
1.project name란에 라이브러리 이름 작성
사용자 삽입 이미지
사용자 삽입 이미지












2.test.c 파일을 생성한다.(함수 정의(구현)부분에 대한 내용)

3.test.h 파일을 생성한다.(함수의 선언부분이 있는곳)

사용자 삽입 이미지

 
//나만의 덧셈 라이브러리 만들기
#include <stdio.h>
#include "test.h"
//덧셈 함수 구현부분
int Add(int a,int b)
{
   return a+b;
}




3.test.h 에 함수에 대한 선언
   ex> int Add(int a, int b);
4.컴파일 하면 Debug 디렉토리 안에 프로젝트명.lib 이 생성

그 다음은 헤더파일을 해당 프로젝트에 넣고 라이브러리 링크
시키면 사용됨.

C로 만든 라이브러리를 C++ 프로젝트에 사용할때는 주의를 하자.
컴파일 과정에서 만들어진 라이브러리의 함수명이 차이가 있다.
C 로 만든 라이브러리는 C프로젝트에서..
C++로 만든 라이브러리는 C++프로젝트에서.. 
다른 방법으로는 위에 글에 설명..

반응형

http://blog.naver.com/guriis/40002401420




첨부파일 (1)

여기에 사용되는 설명은 DLLs for Beginners.Doc 문서에서 발췌 했다.

내가 설명하는 것 보단 훨씬 좋기 때문이다. 물론 난 글을 잘 못쓴다.

DLLs for Beginners.Doc 문서는 첨부 했다.

 

Static Linking(정적 링크)

C, Pascal, FORTRAN와 같은 고 수준의 프로그래밍 언어들에서는, 실행가능한 파일을 생성하기 위해서 응용프로그램의 소스 코드를 컴파일하고 다양한 라이브러리에 링크한다. 이러한 라이브러리들은 메모리를 할당하거나 숫자의 제곱근을 계산하는 것과 같은 일반적인 작업을 수행하기 위해서 호출되는 미리 컴파일된(precompiled) 함수들의 개체(object) 파일을 포함한다. 이러한 라이브러리 함수들이 응용프로그램에 링크될 때, 그것들은 응용프로그램 실행파일에 영구적으로 속하는(permanent) 부분이 된다. 그 라이브러리 함수에 대한 모든 호출은 링크 시간에 결정된다(resolved) - 즉 그 이름은 정적 링크(static linking)이다.

Dynamic Linking(동적 링크)

동적 링크는 실행시간에 응용프로그램이 라이브러리를 링크하는 메커니즘을 제공한다. 그 라이브러리들은 자체의 실행 파일에 존재하며, 응용프로그램의 실행 파일에 정적 링크처럼 복사되지 않는다. 이들 라이브러리들은 동적 링크 라이브러리(DLL)라고 불리우는데, 그것들이 로드되고 실행될 때가 그것이 링크되었을 때가 아니라 응용프로그램에 링크되었을 때임을 강조한 것이다. 응용프로그램이 DLL을 사용할 때, 운영 체제는 DLL을 메모리로 로드하고, DLL 안의 함수들에 대한 참조를 결정한다. 그래서 그것들은 응용프로그램에 의해 호출될 수 있으며, 더 이상 필요하지 않을 때 DLL은 언로드될 수 있는 것이다. 이 동적 링크 메커니즘은 응용프로그램이나 운영체제에 의해서 명시적으로 수행될 수 있다.


1.    File에서 New를 선택해서 Project 탭을 선택한다.

2.    프로젝트 타입 목록에서 Win32 Dynamic-Link Library를 선택한다 .

 

 

 

3.    적절한 프로젝트명을 기입하고, Finish.

 

 

 

이제 DLL을 위한 기본적인 프로젝트 파일이 만들어진 것이다

 

4.    cpp 및 헤더 파일 생성은 알아서 해라.

5.    def 파일은 File-New-C/C++HeaderFile 을 선택하고 파일명 기입시 확장자를 입력하면 된다.

 

MyDLL.cpp

#include <windows.h>

 

BOOL WINAPI DllEntryPoint(HINSTANCE hDllDWORD dwReasonLPVOIDReserved)

{

             switch(dwReason)

             {

                           case DLL_PROCESS_ATTACH:

                                        break;

                                       

                           case DLL_PROCESS_DETACH:

                                        break;   

             }

 

             return TRUE;

}

 

이것은 이 DLL을 사용하는 프로그램들이 이 DLL을 로드하면 DllEntryPoint()가 자동으로 호출이 되는 것이다. 그리고 위의 코드는 switch ~ case 문으로 구성이 되어있다. DLL_PROCESS_ATTACH는 DLL이 EXE에 로딩될 때, 실행된다. 그러므로 초기화에 관련된 코드는 이 곳에 넣어주면 된다. 또한 DLL_PROCESS_DETACH는 DLL이 EXE 파일에서 해제될 때 실행된다. 그러므로 이 부분엔 DLL을 사용하는 EXE 파일이 종료되기 직전에 실행될 부분을 넣어주면 된다.

 

 

int MyFunc(int aint b)

{

    return a*b;

}

int CdeclFunc(int  a)

{

    return  2*a;

}

 

MyDLL.h

int MyFunc(int aint b);

int CdeclFunc(int a);

 

MyDLL.def

EXPORTS

             MyFunc

             CdeclFunc

 

 

 

 

-------------------------------------------------------------------

EXE 프로그램 작성


1.       File에서 New를 선택해서 Project 탭을 선택한다.

2.       프로젝트 타입 목록에서 Win32 Console Application 를 선택한다 .

 

 

 


 

 

 

3.       적절한 프로젝트명을 기입하고, Finish

 

 

 


 

 

APP.cpp

 

#include <windows.h>

#include <stdio.h>

 

void main()

{

             typedef int(*lbFunc1)(int);

             typedef int(*lbFunc2)(intint); // 포인터 함수 사용

 

    int x = 3;

             int a = 3;

 

             lbFunc2 Func2;

 

             HINSTANCE  hLibrary;

             hLibrary = LoadLibrary("MyCPP.dll"); //Load DLL in main

 

             ifhLibrary == 0 ){ //HINSTANCE handle 얻음

        printfNULL, " Load rfm Library failed.", 0 );

exit(0);

    }

 

             Func2 = (lbFunc2)GetProcAddress(hLibrary, "MyFunc"); // 함수 얻음.

             if(Func2 == NULL){

        printfNULL, " Load CMyFunc failed.", 0 );

        exit(0);

    }

            

             a = ((Func2)(x,a));

 

             printf("%d", a);

 

             FreeLibrary(hLibrary); //Free Library in main

}

dll 파일은 Exe 실행파일이 있는곳에 복사 해야 된다. /Debug 밑이나 /Release밑에 복사 하면 된다.

 

 이상 태클 걸지 마라나도 찾아서 알아  거다.

반응형

http://sol9501.blog.me/70102942944


|DLL 분석 ①|DLL파일 생성과 설명

 

* 이번 포스팅은 실제 DLL파일이란 무엇인지 알아보고 직접 생성하는 방법을 알아보겠습니다.

 

 

 1. DLL(Dynamic Link Library)이란?

   1)정의

     - 어플리케이션에서 동적으로 링크하여 사용할 수 있는 라이브러리를 말하며 확장자로는 .dll, .fon, .drv, .exe 등이 사용된다.

구조는 간단히 코드부분과 데이터로 구성되어있으며, 스택이 없다는 것이 특징이다. 스택은 어플이케이션의 것을 사용한다. 스택이 없으므로 독립적인 프로세스가 될 수 없으며 운영체제로 부터의 메세지를 받을 수 없다. 내부에 Exported Function Table을 가지고 있으며 서수 + 기호이름 + 실제함수를 가리키는 포인터로 구성되어 있다.

 

   2) 종류

    - Regular DLL (Statically linked MFC DLL) : 배포시 자신의 DLL만 제공가능

    - Regular DLL (using Shared MFC DLL) : 배포시 자신의 DLL과 MFC공유DLL을 같이 제공

      -> 어플리케이션이 MFC이외의 경우에도 사용가능

      C언어 기반의 인터페이스제공 필요.

     - MFC Extension DLL (using Shared MFC DLL) : MFC로 작성된 어플리케이션에서만 사용가능

 

    3) 로딩방법

     ㄱ) Implicit Loading (암시적 로딩)

        - DLL + Lib + header file 필요. 

- 어플리케이션 로딩때 같이 로딩.

     ㄴ) Explicit Loading (명시적 로딩)

         - 로딩타임 마음대로 결정가능

- 주요함수

- LoadLibrary : DLL모듈 로딩

- GetProcAddress : 함수의 포인터를 얻어옴

- FreeLibrary : DLL 종료 (reference counter를 1감소시킨다)

 

* 이번 포스팅은 DLL 파일 생성 방법만 알아보고 로딩방법이나 기타 자세한 상항은 PE파일 (DLL 로딩과 임포트 섹션편)을 참고해 주시길 바랍니다.

DLL 로딩과 임포트 섹션 - 포스팅중..^^

 

 

  2. DLL 생성

    - DLL을 만드는 방법에는 크게 두 가지가 있다. 하나는 고전적인 DLL정의 방법인 모듈 정의 파일을 이용하는 것이고 다른 하나는 내장 Visulal c++ 지시자인 __declspec(dllexport)를 이용하는 것이다. 우선은 고전적인 방법인 모듈정의 파일을 이용해 먼저 DLL 파일을 생성해 보겠습니다. 소스는 아래와 같습니다. VS2010기준으로 DLL 파일을 생성하는 방법은 아래의 그림 1-1부터 1-3과 같습니다.

 

그림 1-1) win32 project

 

그림 1-2) Application Setting

 

- 그림 1-2에서처럼 어플리케이션 타입은 DLL을 클릭해 줍니다. 프로젝트가 생성되었으면 빈 cpp소스파일을 하나 생성하고 아래의 예제소스를 복사해 붙여 넣고 빌드합니다. 빌드가 성공하면 그림 1-3과 같이 dll 파일이 생성됩니다.

 

Ex1) 예제소스 1

#include <Windows.h>

 

void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos)

{

TextOut(hDC, ptPos.x, ptPos.y, pszText, lstrlen(pszText));

}

 

int IntSum06(int a, int b)

{

    return a+b;

}

 

BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos)

{

    return PtInRect(&rcRgn, ptPos);

}

 

 

그림 1-3) Application Setting

 

- 여기서 잠깐 우리는 저 DLL을 왜 만드는지 짚고 넘어가야 한다. DLL을 사용하는 근본적인 이유는 반복해서 사용하는 코드를(위의 경우 3가지 함수들) 매번 작성할 것이 아니라 따로 바이너리 모듈로 만들어두고 필요할 때마다 링크해서 사용하고자 하는 목적이다. 여기서 확장자가 .lib라는 파일인 정적 라이브러리와 .DLL인 동적 라이브러리로 나뉘는데 이 둘의 차이는 정적 라이브러리는 코드나 데이터가 링크 시에 pe파일 내에 병합되어 그만큼 PE파일의 사이즈가 커지지만 동적 라이브러리의 경우(.DLL) 라이브러리의 코드나 데이터는 해당 PE가 로드 될 때 그 PE의 가상 주소 공간에 병합된다는 것입니다. 즉 링크된 EXE의 PE 파일에는 단지 해당 라이브러이에서 사용할 함수에 대한 간단한 정보만 기록됩니다.(이 부분의 확인은 위에서 링크한 PE파일 익스포트 섹션분석편을 참고하세요.)

모듈 자체가 정적 라이브러리처럼 EXE의 PE이미지 내에 병합되는 것이 아니기 때문에 DLL의 경우 이렇게 실행 이미지에 병합하고자 하는 함수나 변수는 미이 병합될 함수라는 것을 컴파일러나 링커에게 알려주어야 합니다. 이렇게 알려주는 것을 "익스포트"한다라고 하는데 익스포트시키지 않으면 해당 DLL 내의 어떤 함수나 변수를 사용할 수 있는 지 판단한 수 없습니다.

위의 과정은 단지 함수만 정의했을 뿐 그 외 어떠한 것도 지정하지 않았습니다. 즉 익스포트시키지 않은 것입니다. 그 결과 그림 2와 같이 dumbin 으로 익스포트 정보를 요구해도 아무런 정보가 나타나지 않는 것입니다.

이러한 익스포트 하는 방법으로 위에서 언급한 모듈 정의 파일을 정의하거나 __declspec(dllexport) 지시어를 사용하는 방법이 있습니다. 우리는 우선 고전적이고 지금은 사용빈도가 적지만 기본이 되는 모듈 정의 파일을 이용하는 방법을 알아보겠습니다. 제가 항상 말씀드리지만 고수와 하수의 차이는 기본기에 있습니다. ^^ 기초가 튼튼해야죵..^^

 

그림 2) 익스포트 되지 않은 dll파일

 

 

1) 모듈정의 파일 사용

- 모듈 정의 파일의 장점은 서수를 지정할 수 있다는 것이다. 서수를 지정할 수 있다는 이야기는 서수가 익스포트 함수들에 대한 인덱스 역할을 하게 되기 때문에 문자열 비교 없이 빠른 속도로 해당 함수를 링크할 수 있다는 장점이 있다. 또한 DLL에 익스포트 함수를 새로 추가할 때 이 함수에 해당하는 서수를 그 DLL내에서 익스포트된 다른 모든 함수의 서수 값들보다 더 높은 값으로 할달 할 수 있다. 이렇게 되면 암시적 링크를 사용하는 응용 프로그램에서 새로운 함수가 추가된 DLL에 해당하는 LIB파일을 다시 링크할 필요가 없어진다. 이 경우 기존의 DLL에 새로운 기능을 추가하여 계속 업그레이드시키면서도 기존 응용 프로그램이 업그레이드된 DLL과 올바르게 작동하도록 할 수 있다. 또한 만약 익스포트시킬 함수가 많을 경우 모듈 정의 파일을 통해 "NONAME"의 속성을 지정하게 되면 함수 이름을 저장하지 않고 서수만 저장하기 때문에 DLL의 사이즈를 최적화할 수 있다.

아래 그림 3은 모듈정의 파일을 정의하는 방법을 보여주고 있다. 모듈정의 파일은 노트패드나 문서화 도구를 이용해서 아래 그림 3과 같이 만들어 주면 된다.

 

그림 3)모듈 정의 파일(.DEF)

 

- 모듈 정의 파일은 말 그대로 모듈을 정의한다는 의미이다. 이 말은 곧 굳이 작성하는 PE가 DLL이 아니라 exe이더라도 링크 시에 모듈정의 파일에 정의된 지시어들이 유효함을 말하며 링커는 모듈 정의 파일이 존재한다면 이 파일에 지정된 지시어들을 링크 스위치로 해석하게 된다. 일반적으로 모듈 정의문 대신에 사용할 수 있는 링커 옵션이 있기 때문에 일반적으로는 모듈 정의 파일이 필요하지 않다. 하지만 함수 익스포트의 경우 위의 그림 3처럼 EXPORTS 키워드 아래에 익스포트 함수들을 한 번에 정의할 수 있기 때문에 DLL 작성시 모듈 정의 파일을 사용하는 것이다. 각 키워드는 표 1을 참고하세요.

 

[표 1] – 모듈정의 파일

키워드

의미

LIBRARY

형식

LIBRARY [library][BASE=address]

library

* library 옵션은 DLL의 이름을 지정한다. 링커 옵션 /OUT을 사 용하여 DLL의 출력 이름을 지정 할 수도 있다.

BASE=address

* BASE= ADDRESS 옵션은 운영체제가 해당 DLL을 로드하는데 사용하는 기본 주소를 설정한다. 정의되지 않았다면 DLL 매핑의 디폴트 주소인 0x10000000으로 설정한다.

EXPORTS

형식

EXPORTS

definition

definition = entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

entryname

* entryname은 익스포트하고자 하는 함수 또는 변수의 이름으로서 반드시 지정되어야 하는 요소이다. internalname의 경우는 익스포트하고자 하는 이름이 DLL에 있는 이름과 다른 경우에 이 요소를 통해 실제 이름을 지정하기 위해 사용된다.

@ordinal

* @ordinal을 사용하면 함수 이름이 아닌 서수가 DLL의 익스포트 테이블에 들어가도록 지정된다. 이렇게 서수를 지정하게 하면 후에 DLL을 링크하는 응용 프로그램에서는 이름 대신 서수를 통해 해당 함수를 링크하게 된다.

NONAME

* 선택적 키워드인 NONAME을 사용하면 함수를 서수로만 익스포트시키기 때문에 해당 DLL이 많은 익스포트 함수를 정의할 경우에 익스포트 테이블의 크기를 줄일 수 있다. 하지만 링크하고자 할 때 이름이 유효하지 않게 되므로 반드시 서수를 알아야 한다.

PRIVATE

* 선택적 키워드인 PRIVATE는 LINK로 생성된 LIB파일에 ENTRYNAME이 포함되지 않도록 한다.

DATA

* 선택적 키워드인 DATA는 익스포트 대상이 코드가 아니라 데이터임을 알려준다.

EXPORTS

DllExam @1 PRIVATE, DATA

DllName = ValName DATA

DllObject @4 NONAME, PRIVATE

DllRegi

 

 

- 위의 그림 3과 같이 모듈정의 파일을 정의했으면 이젠 다음 그림4와 같이 정의 파일을 프로젝트에 포함시켜주자.

 

그림 4) 모듈정의 파일 추가

 

 

- 위의 그림 4와 같이 모듈정의 파일을 추가했으면 다시 한 번 빌드해줍니다. 그러면 이번에는 lib파일과 exp파일이 생성되었음을 알 수 있습니다. 아래의 그림은 dumpbin으로 다시 한 번 DLL의 익스포트 정보를 확인해 보겠습니다.

 

그림 5) DLL 익스포트 정보

 

 

- 그림 2와 비교하여 이 번에는 예제소스의 함수들이 제대로 익스포트되어 출력됨을 알 수 있습니다. 실행방법은 생성된 lib파일을 실행할 프로젝트에 포함시키고 컴파일 시키시면 됩니다. 아래 그림 6은 실행화면 설명입니다. 소스는 실행파일 소스입니다.

 

 

Ex2) 실행파일 소스 1

#include <windows.h>

 

#define DLL_NAME "DllExam_01.dll"

 

void ChkPrint(LPCTSTR str);

int IntSum06(int a, int b);

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpCmdLine,intnShowCmd)

{

    HMODULE hModule;

    TCHAR buf[512];

 

    hModule = LoadLibrary(DLL_NAME);

 

    

    wsprintf(buf,"hModule = 0x%8x\n",hModule);

    ChkPrint(buf);

    

 

    wsprintf(buf,"hModule = %d\n",IntSum06(5,6));

    ChkPrint(buf);

 

 

    return 0;

}

 

    void ChkPrint(LPCTSTR str)

{

    MessageBox(HWND_DESKTOP,str,"OK",MB_OK);

}

 

 

그림 6) 모듈정의 파일 방법실행

 

 

2) __dlclspec(dllexport) 지시자 사용

- MS에서는 컴파일러에서 익스포트할 함수나 변수의 이름을 자동으로 생성한 다음에 ,LIB 파일에 포함시킬 수 있도록 하였는데 그 때 쓰이는 지시자가 __declspec이다. dexlspec(dllexport) 지시자를 사용하여 dll에서 데이터, 함수, 클래스 또는 클래스 멤버 함수를 내보낼 수 있도록 변경할 수 있다. 그리고 __declspec(dllexport)와 쌍으로 사용되는 키워드가 __declspec(dllimport)이다. __declspec(dllexport)은 컴파일러로 하여금 해당 함수가 익스포트될 것임을 알려준다. 반대로 __declspec(dllimport)는 컴파일러로 하여금 해당 함수가 임포트되는 함수임을 미리 알려주는 역할을 한다. 소스파일과 헤더파일의 소스는 아래와 같습니다.

 

 

Ex3) 소스 1

#include "Windows.h"

 

#ifdef __cplusplus

#define DLLBASIC_API extern "C" __declspec(dllexport)

#else

#define DLLBASIC_API __declspec(dllexport)

#endif

#include "Dll_declspec.h"

 

void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos)

{

    TextOut(hDC, ptPos.x, ptPos.y, pszText, lstrlen(pszText));

}

 

int WINAPI IntSum06(int a, int b)

{

    return a+b;

}

 

BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos)

{

    return PtInRect(&rcRgn, ptPos);

}

 

 

Ex4) 헤더 1

#ifndef __DLLBASIC_H__

#define __DLLBASIC_H__

 

#ifndef DLLBASIC_API

#ifdef __cplusplus

#define DLLBASIC_API extern "C" __declspec(dllimport)

#else

#define DLLBASIC_API __declspec(dllimport)

#endif

#endif

 

DLLBASIC_API void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos);

DLLBASIC_API int WINAPI IntSum06(int a, int b);

DLLBASIC_API BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos);

 

#endif    //__DLLBASIC_H__

 

- 위의 소스가 정의문들이 많아 약간 어려워 하실 분들도 있을 수 있겠지만 실상은 상당히 간단한 문장입니다..

__cplusplus와 extrn "C"는 함수 호출 방법에 따른 스택정리와 이름 데코레이션의 관계때문에 정의해 준 부분입니다. 이 부분을 설명하자면 이번 포스팅의 범위를 넘어가니 이 부분은 따로 관계된 문서를 찾아 보시길 바랍니다.

아래 그림과 같이 소스 파일과 헤더파일을 추가 시키고 빌드 하면 위이 파일정의 모듈방식과 동일하게 LIB파일이 생성됨을 알 수 있습니다. 이 파일을 dumpbin으로 출력해보면 위의 그림 5와 같이 익스포트 정보들이 출력됨을 알 수 있습니다.

 

그림 9) declspec 빌드

 

그림 10) dumpbin 출력화면

 

반응형

방법은 간단하다

 

프로젝트 A, 프로젝트 B 가 있고 B 가 lib 로 생성된다고 하고 A 가 시작프로젝트이며

 

빌드 순서는 B->A 의 종속성이라고 가정하면

 

프로젝트B의 출력디렉토리를 프로젝트A의 'VC++라이브러리' 경로에 추가해준다

 

대부분 B프로젝트의 경우는 출력디렉토리가 $(SolutionDir)$(Configuration)\ 로 지정되어 있음으로 이것을 복사해

 

A프로젝트의 라이브러리 경로에 추가하면 된다


반응형

static link 이든 dynamic link 이든 둘다 라이브러리이다

 

그런데 사용 방법에 있어 좀 차이가 있다

 

상황에 따라 적절한 것을 사용 하면 되겠다

 

 

static link  실행 파일에 라이브러리를 포함하여 배포 : 일반적으로 사용자는 해당 dll 을 가지고 있지 않기 때문에 이 방식으로

배포를 한다

 

static link(debug) 싱행파일에 라이브러리를 포함하는데 debug 할 수 있는 정보까지 같이 배포한다

 

dynamic link 라이브러리를 독립적으로 분리한다, 이점은 하나의 파일만 만들어 짐으로 메모리 점유율이 static link 보단 적다

 

그리고 개발 시 dll 부분에 오류가 있으면 해당 dll 만 수정하여 해당 dll 만 배포하면 된다

 

또한 여러곳에서 동일한 파일로 툴, 엔진 등의 라이브러리 관리를 static link 처럼 종속되지 않고 독립적으로

 

관리 할 수 있어 관리의 용이성이 더해진다

 

 

dynamic link (debug) dynamic link 에 debug 정보를 포함하여 해당 dll 에서의 debug도 가능하게 해준다

 

 

 

반응형

라이브러리란 특정한 코드(함수 혹은 클래스)를 포함하고 있는 컴파일된 파일이

 

 

 

 

라이브러리를 만드는 이유는 자주 사용되는 특정한 기능을 main 함수에서 분리시켜 놓음으로써, 프로그램을 유지, 디버깅을 쉽게하고 컴파일 시간을 좀더 빠르게 할수 있기 때문이다.

 

 

 

 

라이브러리에도 그 쓰임새에 따라서 여러가지 종류가 있다(크게 3가지). 가장 흔하게 쓰일수 있는 "정적라이브러리"와 "공유라이브러리", "동적라이브러리" 가 있다. 이들 라이브러리가 서로 구분되어지는 특징은 (로드) 시간이 될것이다.

 

http://cafe.naver.com/whatvoip.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=202&

 

 

C로 만든 라이브러리를 C++ 프로젝트에 사용할때는 주의 하자. 컴파일 과정에서 만들어진 라이브러리의 함수명이 차이가 있다. C 로 만든 라이브러리는 C프로젝트에서, C++로 만든 라이브러리는 C++프로젝트에서

 

 

 

 

 


정적라이브러리 

 

정적라이브러리는 object file(.o로 끝나는) 의 단순한 모음이다. 정적라이브러린느 보통 .a 의 확장자를 가진다. 간단히 사용할수 있다. 컴파일시 적재(로드)되므로 유연성이 떨어진다. 최근에는 정적라이브러리는 지양되고 있는 추세이다. 컴파일시

적재(로드)되므로 아무래도 바이너리크기가 약간 커지는 문제가 있을것이다.

 

 

공유라이브러리


공유라이브러리는 프로그램이 시작될때 적재(로드)된다. 만약 하나의 프로그램이 실행되어서 공유라이브러리를 사용했다면, 그뒤에 공유라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유라이브러리를 사용하게 된다. 그럼으로써 우리는 좀더 유연한 프로그램을 만들수 잇게 된다.

 

정적라이브러리와 달리 라이브러리가 컴파일시 적재되지 않으므로 프로그램의 사이즈 자체는 작아지지만 이론상으로 봤을때, 라이브러리를 적재하는 시간이 필요할것이므로 정적라이브러리를 사용한 프로그램보다는 1-5% 정도 느려질수 있다. 하지만 보통은 이러한 느림을 느낄수는 없을것이다.

 

 

동적라이브러리


공유라이브러리가 프로그램이 시작될때 적재(로드)되는 반면 이것은 프로그램시작중 특정한때에 적재(로드)되는 라이브러리이다. 플러그인 모듈등을 구현할때 적합하다. 설정파일등에 읽어들인 라이브러리를 등록시키고 원하는 라이브러리를 실행시키게 하는등의 매우 유연하게 작동하는 프로그램을 만들고자 할때 유용하다.

 

 


 

 


정적 라이브러리와 동적 라이브러리 차이  C++ /API/MFC 

2011/10/13 15:15

복사http://blog.naver.com/hacker1420/120142196000

정적 라이브러리(lib) : 컴파일할 때 같이 링크 

동적 라이브러리(dll) : 컴파일 할 떄가 아닌, 실제로 프로그램이 실행될 때 동적으로 링크

 

둘 다 실행 모듈이지만 언제 링크가 되느냐의 차이!

메모리를 효율적으로 쓰기 위해서는 lib 보다 dll 방식이 좋음.(필요할 때만 링크해서 쓰고 필요 없으면 바로 해제)

lib 방식은 프로그램이 실행되면 바로 메모리를 차지하고 프로그램이 종료될 때까지 메모리에 남아있음.

반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..








Dll 예제 파일, 소스안에 설명

 

 

실행 환경 vs2008




p.s 예전에 만들었던것..

3dmp

반응형

'운영체제 & 병렬처리 > DLL_LIB' 카테고리의 다른 글

dll과 lib 배포하기  (0) 2012.11.01
Dll과 Lib 차이와 설명  (0) 2012.11.01
확장 DLL 전역변수 선언 및 사용  (0) 2012.11.01
dllimport과 dllexport  (0) 2012.11.01
__declspec(dllimport)의 호출 원리  (0) 2012.11.01

퍼온글임..

 

 

확장 DLL 전역변수 선언 및 사용

1. 전역변수 사용에 대한 고찰..
: 전역 변수는 파일 내부의 전역변수와 파일 외부의 전역변수로 나뉩니다.

: 파일 내부의 전역변수는.. 그 파일 내에서 유효한 범위를 가지는 변수로
함수의 외부에서 선언하며 그 선언된 아래쪽에서 유효합니다.

: 파일 외부의 전역변수는.. 그 프로젝트에 포함된 다른 소스 파일의 전역변수 중
공통으로 가져다 쓰고자 할 때 사용되며, 포함하고자 하는 소스파일에서는
extern 변수형 변수명..형태로 포함한 후.. 자신의 전역변수처럼 사용할 수 있습니다.

: 아래에 내부 전역 변수와 외부 전역 변수를 구분합니다.

ex) A.cpp ----

#include "stdafx.h"
#include "A.h"

...

int g_nSum = 0; <== 전역변수..일반적으로 Global이라는 뜻의 g_사용(이츠 미)

CA::MyFunc()
{

int nValue = 10; <== 지역변수..함수 내부에서만..유효

m_nKuk = 100; <== 멤버 변수 형태..

g_nSum += (nValue + m_nKuk); <== 전역변수 사용

....

}

CA::PrintSum()
{

printf( "%d", g_nSum );

}

사실.. 클래스 개념으로 오면서.. 전역변수와 멤버 변수는 차이가 없어졌습니다..

도스형 코딩에 익숙한..깨고르..같은 사람은.. 부분적으로 쓰고는 있지만..
멤버 변수와 컨트롤 변수, 전역변수.. 비슷하면서도..조금은 다르더군여..

그렇지만..멤버 변수와 전역변수는 거의 같은거 가타영..!--

-----------------------------------------------------------------------------

B.cpp ---

#include "stdafx.h"
#include "B.h"

...

int g_nSum; <== 이로케..하면.. 내부의 전역 변수가..되어서. A.cpp의
g_nSum 과는 전혀 다른값을 가지게..됩니다.

위의 부분을 외부 전역변수 형태로 만든다면..

int g_nSum ==> extern int g_nSum; 처럼..해주면..됩니다.

즉.. 자신의 파일이 아닌..외부(extern)의 파일에 전역변수 선언되어 있는 g_nSum을 
이용하겠다고 컴파일러에게 알리는 것입니다.

그리고선.. 그냥..자신의 전역변수처럼..쓸 수 있져..!--

2. DLL 내부에서 전역변수 선언하기(외부 전역변수 선언으로..)
: 전역변수의 원형 선언 : __declspec(dllexport) 변수 타입, 변수~명..

ex) __declspec(dllexport) int g_nSum;

: DLL 전체에서 사용하기 위해..extern 선언.. : extern __declspec(dllexport) 변수 타입, 변수~명..

ex) extern __declspec(dllexport) int g_nSum;

+++> 위의 전역변수 선언을 보면.. __declspec(dllexport)외에는 별루 다른게 없어 보입니다.

: 클래스를 확장 DLL로 선언하기..위하여..

클래스의 헤더 선언부에.. class CA::public CWnd
{
요런식으루..선언되어 있는데..
이걸.. 다음과 같이.. 앞쪽에.. AFX_EXT_CLASS 를 붙여서.. 외부로 인터페이스 가능한 클래스라구
컴파일러에 통보합니다.

class AFX_EXT_CLASS CA::public CWnd
{

처럼여..


3. 확장 DLL을 이용하는 프로그램에서..

: DLL에 선언된 전역 변수를 포함해야져.. 
: DLL 전체에서 사용하기 위해.. extern 선언했던 것과 유사합니다.
: extern __declspec(dllimport) int g_nSum;

자세히..보면.. __declspec(dllexport) 가.. __declspec(dllimport)로 바뀐것을
알 수 있습니다.

export는..밖으루.. 오픈될 수 있는..
import는..밖에 선언되어 있는걸..가져올 수 있는.. 이라는..의미를 가진듯 합니다. --;;;


반응형

Microsoft Specific

dllimport, dllexport

DLL에서(로) 함수, 데이터, 개체를 내보내는(가져오는) 속성. 함수를 dllexport로 선언하면, 적어도 export된 함수 스펙과 관련된 .DEF (모듈 정의) 파일이 필요없다. 또한 dllexport는 __export 키워드 (16비트 버전의 VC++에서 사용) 를 대체한다.

declspec(dllexport) 클래스의 클래스 템플릿 특수화(specialization)는 암묵적으로 declspec(dllexport)가 된다. 즉 템플릿은 명시적으로 인스턴스화(==구체화)되고, 그 멤버들은 반드시 정의되어야 한다.

dllexport C++ 함수는 이름장식을 가진 함수를 노출시킨다. C++ 이름장식이 필요없다면, .def 파일 (EXPORTS(MSDN) 키워드)를 사용하거나 함수를 extern "C"로 선언한다.

dllexport와 dllimport는 반드시 declspec과 확장된 속성 구문을 사용해야 한다.

__declspecdllimport int i;

__declspecdllexport void func();

좀 더 보기좋게 다음과 같이 매크로를 쓸 수도 있겠다.

#define DllImport __declspecdllimport )

#define DllExport __declspecdllexport )

정의와 선언

DLL 인터페이스는 일부 프로그램이 export한 모든 항목 (함수와 데이터) 을 참조한다; 즉 모든 항목은 dllimport나 dllexport로 선언되며, DLL에 선언된 것들은 반드시 둘 중 하나를 가져야 한다. 하지만, 그 정의는 반드시 dllexport여야한다. 즉 다음과 같은 코드는 컴파일 에러란 말이다:

DllImport int func() { return 1; } // 둘 다 정의

DllImport int i = 10;

dllexport는 정의를 dllimport는 선언을 의미한다. dllexport와 extern 키워드를 같이 사용하면 강제로 선언할 수 있다; 그렇지 않으면 정의를 의미한다. 다음 코드들을 보자:

extern DllImport int k; // 둘 다 선언을 의미하며 정확하다

DllImport int j;

static DllImport int l; // 에러; extern으로 선언되지 않음

void func() {

static DllImport int s; // 에러. extern으로 선언되지 않음

DllImport int m; // OK. 이것은 선언

DllExport int n; // 에러. 로컬 범위에서 외부정의를 포함

extern DllImport int i; // OK. 이것은 선언

extern DllExport int k; // OK. extern은 선언을 의미한다

DllExport int x = 5; // 에러. 로컬 범위에서 외부정의를 포함

}

dllexport/ dllimport로 선언된 인라인 C++ 함수 정의

dllexport 함수를 인라인으로 선언하면, 어떤 모듈이 그 함수를 참조하던말던 항상 인스턴스화되고 export되며, 다른 프로그램에서 import한다고 가정된다.

dllimport 함수를 인라인으로 선언하면, 그 함수는 확장될 수 있지만 (/Ob(VS6.0) 설정에 따라) 절대 인스턴스화되지는 않는다. 특히 인라인 import 함수의 주소가 있다면, DLL 안에 존재하는 그 함수의 주소가 리턴된다. 이는 인라인이 아닌 import 함수의 주소를 얻는 것과 같은 방식이다.

위 규칙들은 클래스 안에 정의된 인라인 함수에 적용된다. 게다가, 인라인 함수 안의 정적 로컬 데이터와 스트링은 마치 하나의 프로그램 (즉 DLL 인터페이스가 없는 실행 파일) 안에 있는 것처럼 DLL과 클라이언트 사이에서 동일성을 유지한다.

DLL을 업데이트할 때, 클라이언트가 바뀐 DLL을 사용할 거라고 가정하지 않는다. 올바른 버전의 DLL을 로딩하려면, 해당 클라이언트 또한 재빌드한다.

일반적인 규칙과 제한사항

─ dllimport나 dllexport 없이 선언된 함수나 개체는 DLL 인터페이스로 간주되지 않으며, DLL 인터페이스로 만들려면 dllexport로 정의한다. 이런 경우든 dllexport로 선언된 경우든, 같은 프로그램 안에 정의되어야 한다. 아니면, 링커 에러가 발생한다.

─ 하나의 모듈 안에 동일한 함수나 개체가 dllimport와 dllexport 2가지로 선언되면 dllexport 속성이 우선하지만, 이는 파일러 경고를 일으킨다:

__declspecdllimport ) int i;

__declspecdllexport ) int i; // 경고; 불일치; dllexport가 우선한다

─ C++에서는 글로벌/ 정적 로컬 데이터 포인터를 dllimort로 선언된 데이터 개체의 주소로 초기화할 수 있다. 하지만 이는 C에서 에러다. 또한, 정적 로컬 함수 포인터를 dllimport로 선언된 함수의 주소로 초기화할 수 있다. 이 포인터는 C에서 DLL import thunk (함수로 제어를 넘기는 코드 토막) 의 주소, C++에서는 함수의 주소가 할당된다:

__declspecdllimport ) void func1( void );

__declspecdllimport ) int i;

int *pi = &i; // C에서는 에러

static void ( *pf )( void ) = &func1; // C에서는 thunk 주소, C++에선 함수 주소

void func2() {

static int *pi = &i; // C에서는 에러

static void ( *pf )( void ) = &func1; // C에서는 thunk 주소, C++에선 함수 주소

}

하지만 dllexport 개체 선언을 포함하는 프로그램은 반드시 정의도 가져야하므로, 글로벌/ 로컬 정적 함수 포인터를 dllexport 함수의 주소로 초기화할 수 있다. 또한 글로벌/ 로컬 정적 데이터 포인터를 dllexport 데이터 개체의 주소로 초기화할 수 있다. 가령 다음 코드는 C/ C++에서 모두 에러가 아니다:

__declspecdllexport ) void func1( void );

__declspecdllexport ) int i;

int *pi = &i;

static void ( *pf )( void ) = &func1;

void func2() {

static int *pi = &i;

static void ( *pf )( void ) = &func1;

}

─ VC++ .NET에서는 regular 클래스와 클래스 템플릿의 특수화 사이에서 dllexport를 가진 애플리케이션이 보다 일관되도록 하기위해, dllexport가 아닌 기본 클래스를 가진 regular 클래스에 dllexport를 적용하면 C4275(한글) 컴파일러 경고가 발생한다.

이 경고는 기본 클래스가 클래스 템플릿의 특수화일 경우도 발생하는데, 이 때는 dllexport를 표시해주면 된다. 즉 클래스 템플릿에 __declspec(dllexport)을 쓸 수 없다. 대신 다음처럼, 명시적으로 클래스 템플릿을 인스턴스화하고 여기에 dllexport를 사용한다:

template class __declspecdllexport ) B<int>);

class __declspecdllexport ) D : public B<int> {}

이 방법은 다음처럼 템플릿 인자가 부모 클래스인 경우 에러가 발생한다:

class __declspecdllexport ) D : public B<D> {}

이는 템플릿에서 흔한 패턴이기 때문에, VC++ .NET 컴파일러는 하나 이상의 기본 클래스를 가지는 클래스에 적용될 때와 하나 이상의 기본 클래스가 클래스 템플릿의 특수화일 경우 dllexport 구문을 바꿨다. 이 경우 컴파일러는 암묵적으로 클래스 템플릿의 특수화에 dllexport를 사용하며, 위 문장은 문제없이 컴파일된다.

dllexport/ dllimport를 C++ 클래스에서 사용하기

dllimportdllexport로 클래스를 선언하면, 그 클래스 전체가 import/ export되며, 이렇게 export된 클래스를 exportable 클래스라 한다.

#define DllExport __declspecdllexport )

class DllExport C {

int i;

virtual int func( void ){ return 1; }

};

참고 exportable 클래스의 멤버는 dllimport와 dllexport를 명시적으로 쓸 수 없다.

─ dllexport 클래스는 모든 멤버함수와 정적 데이터멤버가 export되므로, 동일 프로그램 안에서 모든 멤버를 정의해야 한다. 그렇지않으면 링커에러가 발생한다. 단 순수 가상함수의 경우 예외이며, 가상 클래스의 소멸자는 항상 기본클래스의 소멸자에서 호출되므로, 순수 가상 소멸자는 반드시 정의해야 한다. 이 규칙들은 exportable 클래스가 아니더라도 적용된다.

클래스타입의 데이터나 클래스를 리턴하는 함수를 export하려면, 클래스를 export해야만 한다.

─ dllimport 클래스는 모든 멤버함수와 정적 데이터멤버가 import된다. 비클래스 타입에서의 dllimportdllexport와는 달리, 정적 데이터멤버는 dllimport 클래스가 정의된 프로그램에서 정의할 수 없다.

─ exportable 클래스의 모든 기본 클래스는 exportable이어야 한다. 아니면, 컴파일러 경고가 발생한다. 게다가, 클래스이기도 한 모든 accessible 멤버는 exportable이어야 한다. 이로써 dllexport 클래스는 dllimport 클래스로부터 상속받을 수 있고, dllimport 클래스는 dllexport 클래스에서 상속받을 수 있다 (후자는 권장되지 않는다). 대개, (C++ 접근 규칙에 따라) DLL 클라이언트에서 accessible한 모든 것들은 exportable 인터페이스의 일부여야 한다(should). 이는 인라인 함수에서 참조되는 private 데이터멤버에도 해당된다.

End Microsoft Specific

출처 : http://redsky84.tistory.com/entry/declspec-%ED%99%95%EC%9E%A5%EB%90%9C-%EC%86%8D%EC%84%B1-%EA%B5%AC%EB%AC%B8-III

원문: C++ Language Reference, __declspec, dllexport/ dllimport(CE3.0)

참고: VC++ 개념, 가져오기 및 내보내기

반응형


DLLIMPORT / DLLEXPORT  MFC 

2008/01/25 14:41

복사http://blog.naver.com/niceyjb1024/46810517

dllimport와 dllexport는 DLL에서 function, variable, ***(class..)
를 import하거나 export하기 위해 사용합니다.

자세히 말하자면 DLL을 사용하는 프로그램이 DLL로 부터 function등을
가져다 쓰게 하기 위해 외부로 노출(?)시킬 필요가 있는데(.. 이런
함수, 데이터, 개체등을 DLL의 인터페이스라고 하죠..)
이런 목적으로 DLL내의 함수등을 정의할때 dllexport지시자를 붙여 줍니다.
그리고 dllexport를 사용한 함수등에 대해 일반적으로 DLL의 인터페이스를
정의해 두는 DEF파일(Module definition file)에 포함시킬 필요가 없습니다.

반대로 DLL을 가져다 쓰는 프로그램(or 다른 DLL)쪽에선 DLL의 인터페이스
를 사용하기 전에 당연히 미리 선언해 주어야 할 필요가 있습니다. 이때
선언문에서 dllimport 지시자를 함께 사용해 주는 것이죠..

__declspec( dllexport ) int func()
{
return 1;
}

....

__declspec(dllimport) int func() ;

이런 식으로 말이져..

함수의 경우에는 반드시 dllimport를 쓸 필요는 없지만
컴파일러가 좀더 효율적으로 코드를 만들어 주기때문에
함께 써주는 게 좋습니다. 그러나 변수등의 경우에는
꼭 dllimport를 붙여 줘야 함다.

[출처] DLLIMPORT / DLLEXPORT|작성자 완전초짜


 

 


 

 


 

__declspec(dllimport)의 호출 원리  Windows / Programming 

2009/01/28 09:12

복사http://blog.naver.com/iwillhackyou/110041460983

DLL을 통해서 함수를 제공하려면 DLL상의 Export Address Table(PE 포멧)에 함수의 위치를 나타내도록 __declspec(dllexport)지시자를 사용해서 함수를 노출시킨다. 반면에 함수를 호출하는 쪽에서는 특별한 코드 없이 헤더파일(.h)에 포함된 함수 이름을 직접 사용하면 링커가 해당 함수를 호출할 수 있도록 컴파일 시점에 연결시켜준다. 함수를 호출하는 쪽에서 사용한 헤더파일(.h)에 함수 원형이 __declspec(dllimport)으로 정의되지 않았도 정상적으로 DLL에서 제공된 함수를 사용 할 수 있다.

 

즉 다른 모듈에서 제공되는 함수를 호출하는데 있어서 함수 원형에 __declspec(dllimport)이 선언 유무와는 상관없이 항상 호출할 수 있다. 하지만 결론 부터 말하면 DLL에서 제공되는 함수를 사용할 때에는 항상 함수 선언 앞에 __declspec(dllimport) 지시자를 사용하는 것이 좋다.


대부분 DLL에서 제공되는 API는 헤더 파일에 다음과 같이 선언해서 제공한다.

 

// API Export/Import Header

#ifdef CALLEE_EXPORTS
#define CALLEE_API __declspec(dllexport)
#else
#define CALLEE_API __declspec(dllimport)
#endif

CALLEE_API DWORD __stdcall no_no_stdcall(DWORD);  // WINAPI
CALLEE_API DWORD __cdecl no_no_cdecl(DWORD);   // CDECL
CALLEE_API DWORD __fastcall no_no_fastcall(DWORD);

 

위 헤더 파일의 핵심은 모듈을 제공하는 쪽과 사용하는 쪽에서 동일한 하나의 헤더 파일을 공유해서 사용하도록 하는 것이다. (소스 관리 차원에서도 하나의 파일을 유지하는 것이 좋다. 특히 ThirdParty 벤더에서 제공되는 API모듈이라면 더욱더 그렇게 해야한다.)

즉, 프로젝트의 Preprocessor definitions에 특별히 CALLEE_EXPORTS를 선언하지 않은 사용자의 프로젝트에서는 함수를 __declspec(dllimport)형식으로 정의해서 링크하게 된다. 위의 예는 가장 확실하게 __declspec(dllimport)를 선언해서 사용할 수 있는 경우이고 헤더가 중복해서 관리해야하는 어려움도 필요없는 최적의 상태이다.



하지만 내부 프로젝트 모듈이건 다른 벤더의 모듈이던 위와 같이 정의해서 사용하지 않고 다음과 같이 API의 Import용으로 헤더 파일을 별도로 정의해서 제공하는 경우가 종종 있다.

 

 

// API Import Header

DWORD __stdcall no_no_stdcall(DWORD);  // WINAPI
DWORD __cdecl no_no_cdecl(DWORD);   // CDECL
DWORD __fastcall no_no_fastcall(DWORD);


이 경우는 소스 코드상의 헤더 관리의 어려움을 떠나서 성의가 없는 경우이다 -_-.

DWORD __stdcall no_no_stdcall(DWORD);
__declspec(dllimport) DWORD __stdcall no_no_stdcall(DWORD);  


일단 DLL을 static link 할 경우에 링커는 위의 두가지 경우를 구분없이 모두 정상적으로 처리해서 함수를 호출할 수 있도록 한다. 그렇다면 차이점이 무엇일까?
DWORD __stdcall no_no_stdcall(DWORD) 와 같이 선언된 상태에서 링커는 DLL과 함께 생성된 Lib 파일에서 가르키고 있는 Stub을 직접 호출하도록 한다. 컴파일러는 no_no_stdcall() 이라는 함수가 현재 프로젝트 내부에 다른 Obj에 선언된 함수인지 아니면 아예 다른 외부 모듈(DLL)에 선언된 함수인지 현 빌드 시점에는 알 수 없기 때문이다.

 

이렇게 static link용 Lib의 stub에 연결된 경우에도 실행시 실제 DLL의 함수는 정상적으로 호출된다. 그 이유는 DLL 생성시점에 함께 생성되는 Lib 파일의 Stub내부에는 실제 모듈(DLL)의 함수로 점프할 수 있는 코드가 이미 DLL 파일의 컴파일 타임에 이미 생성되어 Stub안에 존재하기 때문에 가능한 것이다. 즉 해당 Stub을 내부 함수처럼 호출하면 그곳에서 실제 모듈(DLL)의 함수를 가르키는 IAT(Import Address Table)를 참조해서 실제 API로 이동하는 코드가 수행되는 것이다. 


즉, DLL에서 제공되는 함수를 호출하는 쪽에서 사용한 함수의 선언 형태에 따라서 아래와 같은 두가지 형태의 코드 형식으로 호출할 수 있게 된다.

 

// 1. 함수원형 앞에 __declspec(dllimport) 지시자를 사용해서 호출할 경우
0x01002000 : CALL DWORD PTR [0x56780000]; // CALL DWORD PTR[_imp__MyFunc];


// 2. __declspec(dllimport) 지시자 없이 호출할 경우
0x01002000 : CALL 0x12340000;
0x12340000 : JMP DWORD PTR[0x56780000];



// (0x5678000 : 실제함수주소를 가르키고있는 IAT의 주소)

...

 

상기 코드 중에서 당연히 1번의 경우가 훨씬 효과적인 것을 알 수 있다. 2번의 경우에는 JMP를 위한 추가적인 5Byte의 Stub 코드를 더 수행하게 되므로 비효율적이다.

__declspec(dllimport)지시자를 사용함으로서 1번의 형태로 DLL에 제공되는 함수를 호출하는 것을 알 수 있다. 상기 코드에서 컴파일러는 __declspec(dllimport) 지시자를 보았을 경우에 실제 함수인 "MyFunc"을 참조하지 않고 "__imp__MyFunc"을 참조하는 코드를 만들어 놓는다. 그후에 링커는 함수 이름에 붙어있는 "__imp__" 라는 Prefix를 보고 외부 DLL에 존재하는 함수를 직접 호출하는 것을 알게 된다. (컴파일리가 링커에게 DLL에 존재하는 함수를 호출한다는 것을 알려주기 위해 "__imp__" Prefix를 함수앞에 추가한다.) DLL과 제공되는 Lib파일에는 "__imp__" prefix를 가지는 함수명이 함께 선언되어 있다.)

 

다음과 같은 링크 에러를 보면 실제 함수 이름 앞에 "__imp__" Prefix가 존재하는 것을 알 수 있다.

 

: error LNK2001: unresolved external symbol __imp__MyFunc

: fatal error LNK1120: 1 unresolved externals

 

위의 경우에는 링크 에러가 발생했는데 링크 에러가 발생하지 않으려면 빈 Lib안에 __imp__MyFunc에 대한 Stub이 존재하고 있어야 한다. DLL과 함께 생성된 Lib에는 "MyFunc", "__imp__MyFunc"에 대한 두가지 Stub이 모두 존재하고 있다. 컴파일러는 두 함수 이름을 Lib에 미리 생성해 놓고 있다.

 

반응형


GetProcAddress() - dll 함수 사용  API 

2008/03/12 10:54

복사http://blog.naver.com/silver6688/60048943503

FARPROC WINAPI GetProcAddress(
  HMODULE hModule
,
  LPCSTR lpProcName
);

솔직히 위에 명령어는 딱히 설명이 필요 없을 정도로 많이 사용하는 핵심 명령어임에 틀림없다.

 

그럼에도 불구하고 흥미로운 부분도 꽤나 숨어있는 녀석이다.

 

    HMODULE pTestDXLib;
    FARPROC pFunctionality;

    pTestDXLib=LoadLibrary("DSOUND");

    pFunctionality = GetProcAddress(pTestDXLib, (char*) 7);

 

 

위와 같이 Ordinary Number를 이용해서 원하는 함수를 호출할수도 있다.

 

typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);

HINSTANCE hDLL;               // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer


hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
   lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1");

      FreeLibrary(hDLL);
      return SOME_ERROR_CODE;
   }
   else
   {
      // call the function
      uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
   }
}

일반적으로는 위에서 처럼 함수 이름으로 호출할 것이다.

 

 

또한 함수 이름뿐만 아니라 변수 이름을 적어서 익스포트된 변수 이름도 쉽게 구할수가 있다.

 

 

extern "C" _declspec(dllexport)
int k=50;//DLL이나 exe와 같은 실행 모듈에서 이렇게 해준다.

 

 

HINSTANCE hInst=GetModuleHandle(NULL);
int* p;
p=(int*)GetProcAddress(hInst,"k");

 

위에 경우는 바로 변수에서 읽어드리는 과정이다. 흥미롭지 않는가?

반응형

http://blog.naver.com/ysoftman?Redirect=Log&logNo=20095032204

 

 

C:\Program Files\Microsoft Visual Studio 9.0\VC

 

의 경로까지 가서 cmd 창에서 해당 경로에서 실행 해야 한다

반응형

프로젝트의 속성에서 출력형태를  클래스 라이브러리로 변경하여 빌드하면됨

반응형

#ifdef EXPORTRULE 
#define MYDLL __declspec(dllexport) 
#else 
#define MYDLL __declspec(dllimport) 
#endif 

이 같은 매크로를 이용해서 DLL 클래스를 작성하였고 

코드:
//--- "myclass.h" ---
class MYDLL CMyClass
{
private:
   CMyClass() {}
   ~CMyClass() {}
 
public:
   static const int SEVEN = 7;
   static const float PI;
};
 
//--- "myclass.cpp" ---
#include "myclass.h"
const float CMyClass::PI = 3.14f;
 
//--- "main.cpp" ---
#include "myclass.h"
int main()
{
   printf("%d", CMyClass::SEVEN); // OK
   printf("%f", CMyClass::PI); // LNK2001
}


위와 같이 컴파일 할 경우 CMyClass::PI에 대해서 LNK2001 에러가 발생합니다. 
static const int 같은 경우는 헤더에서 초기화 및 링크가 잘 되는데 
static const float의 경우 LNK2001 에러가 발생합니다. 

이런 경우 함수를 사용하거나 define 혹은 전역 변수를 쓸 수 밖에 없는지 
고수님들의 의견을 듣고 싶습니다. 
감사합니다.

 

 

 

static const int는 컴파일 단에서 인라인으로 처리 가능한데요 

int 이외의 것들은 그렇지 못하기 때문에 static 변수를 dll로 노출 시키지 못하는 환경 때문에 링크 에러에 거릴겁니다

 

 

반응형

 
 _declspec(dllexport) 또는 _declspec(dllimport) 정적 변수 정의가 여러 개 있는 클래스를 사용하여 첫 번째 변수를 제외한 모든 생성될 C2487 오류가 발생할 수 있습니다. 예를 들어, 이 클래스 선언을 참조하십시오:
 
class _declspec(dllexport) MyClass
{
public:
static int i,j,k;
};
  
 
이 클래스 선언은 이러한 오류가 발생하는 경우를 보여 줍니다. 
오류 C2487: 'j': DLL 인터페이스 클래스 멤버는 DLL 인터페이스를 사용하여 선언할 수 없습니다
오류 C2487: 'k': DLL 인터페이스 클래스 멤버는 DLL 인터페이스를 사용하여 선언할 수 없습니다
각 정적 변수 선언을 자체 줄로 이동하십시오. 위의 클래스 완전히 컴파일할 수 있도록 문제를 해결하려면 이 사용합니다: 
 
class _declspec(dllexport) MyClass
{
public:
  static int i;
  static int j;
  static int k;
};

반응형

http://blog.naver.com/kimgudtjr?Redirect=Log&logNo=140096145411 에서 인용한글


[두번째 방법 : __declspec(dllexport) 지시자 사용방법 ]

위에서는.def 파일을 이용했는데 이 방식은 예전 16비트 시절부터 쓰던 옛발 방식이라고 한다..

여기서는 다은방법을 보자면. 해당 수출하려는 함수에 export 하려는 함수 앞에

__declspec(dllexport) 라는 키워드를 쓰면 된다고 한다. -_-ㅋ

근데 여기 책에서 설명하는 방법은 좀 복잡하고 요상하게 쓰는데 -_-ㅋ 일단 아래를 따라가보자..


여기서는 __declspec(dllexport) 를 쓸대  

1. __declspec(dllexport) 용 test.h 라는 헤더파일을 만든다.


2. __declspec(dllexport) 용 test.cpp 라는 함수 구현 파일을 만든다.


------------------ test.h ---------------------------

#ifndef __DLLBASIC_H__
#define __DLLBASIC_H__

#define DLLBASIC_API
#define DLLBASIC_API extern "C" __declspec(dllimport)

DLLBASIC_API int Sum(int a, int b);

#endif
  
------------------------------------------------------

위의 Sum 함수는 실제로 책에는 다른 함수로  되어있지만  책의 함수가 조금 복잡해서

독자가 이해하기 휩게 하기 위해 단순하게 바껏다.


----------- test.cpp --------------------
#define DLLBASIC_API extern "C" __declspec(dllexport)

#include "test.h"

int SumIint a, intb)
{
 return a+b;
}

------------------------------------------------------

책에서는 이렇게 사용한ㄷ고 되어있다..

사실 test.cpp위에 부분에 보면 DLLBASIC_API 를 먼저 정의하고 test.h 파일을 포함하기 때문에

test.h 파일에 있는 dllimport 는 아무 의미없이 되고 전부다 dllexport로 대체 될것이다.

근데 굳이 이렇게 해더 파일에는 dllimport 를 쓰고 cpp에는 dllexport를 써서 복잡하기 하는 이유가

독자는 너무 긍금했다.. 하지만 책에 잘 설명이 되어있었다.... 하지만 ..-_-ㅋ 보고도 이해를 잘 하지 못했따.. -=_-ㅋㅋ

일단 책에 나와있는 설명을 그대로 옮겨보겠지만.. 혹시라도  아시는분 있으면 알려주길 바란다....

--- 책의 설명.. --------

하지만 왜 이렇게 따로 전처리기 까지 사용해서 복잡하게 dllimport까지 지정하는 것일까???

후에 해당 DLL 사용 시 test.h를 인클루드하게 되면 별도의 DLLBASIC_API라는 매크로를 정의하지 않기 때문에

해당 DLL을 사용하는 입장에서의 DLLBASIC_API는 __declspec(dllimport)로 정의 된다. 그렇게 되면 자연스럽게 헤더에 선언된 함수가

임포트 할 함수임을 미리 컴파일러에게 알리는 역할을 한다. 물론 굳이 알리지 않아도 사용하는 데에는 전혀 문제가 없다.

하지만 이렇게 임포트 함수임을 미리 알리느냐 알리지 않느냐의 미묘한 차이는 실제 PE이미지가 생성될 때 조그만한 차이를 불러온다.

그 차이는 5장 DLL 로딩과 임포트 섹션에서 논의하도록 한다.

------------------------------------------------------------------------
라고 되어있다 -_-ㅋ 먼말인지 몰것다. 그냥 재꼈다 -_-ㅋ

그러면 해당 dll파일을 dumpbin /export test.dll 이라고 해서 확인해보자

글엄 export 된 함수들을 볼수 있다.. 다만 이경우에는

서수를 사용자 임의대로 붙일수 없다고 한다. ..

그래서 서수를 지정해서 사용하는 방법은 포기해야 한다고 한다 -_-ㅋ






[익스포트 함수명의 문제 함수 호출 방식 - 파스칼 방식 C선언 방식 ]


1. 예전엔 아래와 같이 함수 호출 방식이 2가지였다고 함.
   - 하나 : 파스칼방식 
   - 둘    : C선언 방식

2. VC++ 에서 이 두가지 방식의 스택 이용방식을 통일했다고 함.. 둘다 왼쪽에서 오른쪽으로.. ..
   스택이용방식에 있어선 파스칼 방식으로 채택....  
   스택제거 시점은 아직 구분했다고 했다고함.. 아래와 같이 ...


 -------------- C언선방식 -----------------

함수매개변수 : 매개변수를 오른쪽에서 왼쪽으로 스택에 push 한다.

스택제거      : 함수를 호출한 쪽에서 스택을 제거 한다

키워드 :    : __cdecl

아무것도 정의 안하면 디폴트로 C선언 방식으로 된다.
------------------------------------


 -------------- 파스칼방식 -----------------
 
함수매개변수 : 매개변수를 왼쪽에서 오른쪽으로 스택에 push한다.

스택제거     : 함수가 호출된 쪽에서 스택을 제거

키워드         :  __stdcall

_stdcall  또는 WINAPI 를 함수 앞에 쓰면 파스칼 방식으로 된다.
------------------------------------


그리고 자세히보면 위 코드에

#define DLLBASIC_API extern "C" __declspec(dllexport)

라고 되어 잇는데 extern "C" 를 유심히 보자..

이 부분을 제거하고 컴파일 한후  dumpbin /EXPORTS test.dll 한번해보고

이 부분을 제거 하지 말고  컴파일 한후 dumpbin /EXPORTS test.dll 해보라..

그러면 export 되는 함수 이름이 다를 것이다.

extern "C" 라는 키워드는 C언어 형식으로 함수 이름을 짓고

extern "C" 를 제거하면 C++ 규칙대로 함수 이름을 짓는다..

extern "C" 방식은 모든 컴파일러에서 알아볼수 있는 형식이므로

extern "C" 방식으로 함수를 작성하면 다른 컴퓨터에서 무리 없이 돌아가지만

extern "C"를 제거한 C++ 방식으로 함수를 작성하면

함수이름이 이상하게 변하는데 그 이상하게 변환하는 규칙이 각각 컴파일러 마다

제각각이여서 다른 컴퓨터와 호환이 되지 않는다..

그래서 함수를 export 하고자 할때는 위의 extern "C" 키워드를 꼭 붙인다고 한다.

------------------------------------------------------------------

이렇게 함수이름을 어떤 형식으로 짓냐는 방법을

이름 데콜이션 이라고 한다.. 그 규칙이 버전별로 조금씩 다른데....................

독자는 귀찮아서.. 그냥 이 부분은 넘기려고 한다. -_-ㅋ

반응형





정적 라이브러리는 #include<stdio.h> 와 같이 인클루드 시키는 printf,scanf 와 같은 함수들이 있는 라이브러리

=> 컴파일시에 해당 라이브러리 코드가 실행 파일과 합쳐진다.

printf문을 쓰는 5개의 프로그램이 있다면


| 프로그램 1  (printf코드) |
| 프로그램 2  (printf코드) |
| 프로그램 3  (printf코드) |
| 프로그램 4  (printf코드) |
| 프로그램 5  (printf코드) |

와 같이 각각의 프로그램마다 printf 코드가 들어간다.. 왜냐 하면 컴파일시에

정적으로 해당 라이브러리 가 합체되어 컴파일 되기 때문이다.

그래서 똑같은 코드가 프로그램마다 합쳐저서 용량이 늘어나는 단점이 있다..



DLL = 동적 링크 라이브러리 Dynamic link Library

하지만  동적링크라이브러리는 다르다...

해당 라이브러리는 일단 메모리에 한번 올리고..

프로그램들이 그 라이브러리를 필요할때 메모리에 올라와 있는걸 가져다 쓰기만 하면된다.

만약 printf 코드를 동적라이브러리로 만들었다고 가정하고

그 동적라이브러리를 쓰는 5개의 프로그램이 있다면


-----------  메모리 ---------------
|  메모리에 printf 라이브러리 코드 딱 한번 로드 (주소 0x10001050) |
-----------  메모리 ---------------


| 프로그램 1 (0x10001050) 호출) |
| 프로그램 2 (0x10001050) 호출) |
| 프로그램 3 (0x10001050) 호출) |
| 프로그램 4 (0x10001050) 호출) |
| 프로그램 5 (0x10001050) 호출) |


해당 프로그램들은 덩치큰 라이브러리 코드들은 포함하고 있는게 아니고

그냥 해당 코드가 있는 메모리 주소를 불러오는 간단한 하고 조그만한 코드가 있으므로

프로그램 용량이 줄어들것이다..

---------------------------------------------------------------





글엄 간단한 DLL파일을 만들어 보자..

비주얼 c++ 6.0 에서 프로젝트 만들때  Win32 Dynamic-Link Library  라는 옵션을 주어서

만들면 된다. 아래에서 아주 간단한 함수 하나를 만들어보고  이 함수를 export 시켜서

일반 실행파일에서 쓰는 예제를 만들어 보자

------------------- test.cpp ----------------------

int Sum(int a, int b)

{

 return a+b;

}

---------------------------------------------------------------

다.. 만들었다... 죠낸 간다하다 -_-ㅋ 그렇다.

그냥 두 수를 인자로 받고 더 해서 결과를 리턴해주는 아주 죠낸 초 간단 함수이다.

이 함수를 dll파일로 만들었으니.. 이 함수는 동적링크 라이브러리 되시겠다... 

WinMain 필요없다.. main 도 필요없다.

그냥 우리가 필요한 함수만 딱 써놨다.. 그래도 된다.. -_-ㅋ


컴파일하면 test.dll 파일이 생성될것이다.



그렇다면 이 dll파일을 사용하는 일반 실행파일을 만들어보자..

일단 이 dll파일을  실행하려는 실행파일에 같은 폴더에 넣는다..

그리고 해당 실행파일이 이 dll을 불러오고.. 그리고 또  dll 않에 있는 함수를

사용하는 예제는 아래와 같다.




------------------ usedll.cpp ------------------

#include <windows.h>

#define DLL_NAME "test.dll" // 불러 오려는 dll 이름이다.
#define DLL_FUNC "Sum" // 불러 오려는 함수 이름이다.


void Error(LPCTSTR str);
void Printf(LPCTSTR str);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
 HMODULE hModule;
 LPVOID lpFunc = NULL;
 TCHAR buf[512];

 hModule = LoadLibrary(DLL_NAME);

 if(!hModule)
 {
  Error("LoadLibrary Error");
 }
 else
 {
  wsprintf(buf,"hModule = 0x%8x\n",hModule);
  Printf(buf);
 }

 lpFunc = GetProcAddress(hModule,DLL_FUNC);

 if(!lpFunc)
 {
  Error("GetProceAddress Error");
 }
 else
 {
  wsprintf(buf,"lpFunc = 0x%8x\n",lpFunc);
  Printf(buf);
 }

 return 0;
}

void Error(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"ERROR",MB_OK);
 ExitProcess(1);
}

void Printf(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"OK",MB_OK);
}

---------------------------------------------------------------




우의 코드는 실제로 함수를 사용하지 않고 그냥 dll을 로드하고 그 함수 주소를 얻어오는 코드인데

일단 함수 주소만 알면 언제든지 불러올수 있으므로 함수 주소를 얻는 코드까지만 작성했다.

이상이 없다면 모듈주소와 함수주소가 출력될것이다.

하지만 안타깝게도 위의 실행파일을 실행하면 DLL 파일은 찾을수 있지만

함수 주소는 찾을 수 없다는 에러를 발생시킨다......

그 이유는 .... 그 이유는... 그 이유는.....

dll 않에서 만든 함수는 외부로 수출???(export) 되야 하는 것이다.. 이것들은 특별하기 때문에

컴파일시에 이 함수는 외부로 링크될 함수야!!!!!! 라고 알려줘야 한ㄷ고 한다.......... 우리는 그 작업을 안한 것이다. -_-;;;


콘솔창으로 들어가서 해당 dll 파일이 있는 위치로 이동후

dumpbin /EXPORTS test.dll      <-- 라고 쳐보자... 이 명령어는 해당 dll 파일에서 export (수출하는 함수?) 리스트를 보여달라고 하는것이다.

결과 화면을 보면 수출하는 함수가 없다고 뜰 것이다...


그러면 export를 수출 하는 두가지 방법이 있다고 하는데.. 그 방법을 살펴보자

첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)

두번째 방법 : __declspec(dllexport) 지시자 사용




[첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)]


비주얼 컴파일에 프로젝트에서 소스파일 추가 하여 확장자를 .def 라고 하고 cpp 파일과 동일한 파일명으로 하나 만든다.

그리고 그 .def 파일에 다음과 같이 써보자


----------------------- dll.def --------------------------------------------

LIBRARY  
EXPORTS
 Sum   @1

---------------------------------------------------------------

LIBRARY  DLL      <-- 라이브러리 이름이다..

EXPORTS                                   <-- export (수출) 할 함수들 리스트 들

 Sum <-- 함수명  @1    <-- 서수지정..

---------------------------------------------------------------


대략 설명은 이렇다... 이렇게 def 파일을 정의하고 다시 컴파일 한 후!!!

생성되는 dll 파일을 다시 dll을 이용하는 실행파일에 넣고 하면!!

아무런 에러 없이 함수 주소를 가져올 것이다.

그리고.. dumpbin /exports test.dll 이라고 하면 전에 없던 export 라는 부분에서 수출하려는 함수 목록으로 Sum이라는 함수가 나타날 것이다...

 

 




반응형

요즘은 소프트웨어를 개발시 주프로그램과 독립적이면서 작은 기능을 수행하는 여러 작은프로그램을 분리해서 개발하게 됩니다. 작은 프로그램은 보통 dll(dynamic link library) 형태로 구현하며, 주프로그램과 소스상에서 분리되며 실행시 주프로그램과 동적으로 연결되게 됩니다.

소스상에서 이둘의 통신은  함수호출을 통해서 이루어집니다.

dll은 외부에서 자신의 기능을 사용할수 있도록 호출가능한 함수들을 제공합니다. 반대로, 주프로그램은 외부에서 호출할수 있는 함수들을 제공하지 않습니다.

 


 

만일, 주프로그램이 DLL에게 어떠한 작업요청을 한후, 이 작업이 완료되었을때 DLL로 부터 응답을 받고 싶은 경우가 생겼다고 하면 어떻해야 할까요?

이 경우, 주프로그램은 외부에서 호출가능한 함수를 제공하지 않으므로, 호출받고 싶은 함수의 포인터를 DLL에 넘겨준후, DLL에서 호출하도록 구현해야 합니다.

 

다음은 dll에 주프로그램내 호출될 함수포인터의 등록과 dll에서 함수포인터 호출에 대한 간단한 소스입니다.

 

dll 내부

 

//registerfuncptr.h

long DECLSPEC__ __cdecl  SetCallbackProcAddr(long fuctionPtr, int type);

void (*successfptr)(); //함수포인터 선언

void (*failfptr)();

 

//registerfuncptr.c

#include "registerfuncptr.h"

// 함수포인터 등록
long DECLSPEC__ __cdecl  SetCallbackProcAddr(long fuctionPtr, int type)
{
  long Result    = 0;
  if(type == 1)
  {
   successfptr = fuctionPtr;
   if(successfptr != NULL)
      Result = 1;
  }
  else if(type == 2)
  {
   failfptr= fuctionPtr;
   if (failfptr!= NULL) 
    Result = 1;
  }

  return Resul;

}

 

//함수포인터 호출

void work() {

...

   // 작업성공

  if(bState)

     (*successfptr)();

   //작업실패

   else

      (*failfptr)();

}

 

 

주프로그램

 

//response.h

void register();

void success();

void fail();

 

//response.c

void register()

{

   SetCallbackProcAddr((long)(&success)   ,1);

   SetCallbackProcAddr((long)(&fail)   ,2);

}

 

void success() {

...

}

 

void fail() {

...

}


반응형

다음과 같이 선언 되어 있다고 가정한다

어떤 .h 파일에서...

class NineTile{
public :

static CRect mTileRect;

static void SetTileRectSize( CRect TileSize ){
mTileRect = TileSize; 
}
}




main.cpp 가 아닌 어느 cpp 파일에서 Ninetile 의 static 함수로 접근하여 멤버변수 static CRect mTileRect;

에 접근하려고 하면  NineTile.cpp 에 static CRect NineTile::mTileRect; 의 멤버 초기화를 쓰면 안되는 경우가

발생한다..,  다른 프로젝트에서 만들어진 Dll 파일을 다른 cpp 에서 읽어들여 사용 하는 경우.

호출은 아래에서와 같이 main 이 아닌 어느 cpp

CRect tempTileRect = CRect(0,0, pMapLayerData->miTileWidth,pMapLayerData->miTileHeight );
NineTile::SetTileRectSize(tempTileRect );





어떤 cpp 파일에서 static 함수를 호출 한 후 nineTile 의 static 멤버에 접근하려면

어느 cpp 위에 CRect NineTile::mTileRect;  의 static 변수 선언 문이 있어야 에러가 나지 않는다...


dll 에서 읽어 온것인지라 static 변수 선언을 양쪽에서 해줘야 하나 ????
 

 
 
 
프로세스간 static 변수 공유
 
dll은 기본적으로 코드 공유를 위한 목적으로 사용됩니다.
즉, dll에서 사용되는 데이터 값은 dll을 사용하는 애플리케이션 간에 공유되지 않죠.

예를 들어, dll 안에 static int g_nCount = 0; 라는 값이 있을 때, 
dll에서 export하는 Increase라는 함수를 호출하면 g_nCount++; 라는 구문이 실행되고, g_nCount 값을 리턴한다고 가정하죠.

이 때, 서로 다른 2개의 애플리케이션(즉, 프로세스)에서 
이 dll을 로딩하고 Increase를 호출하면 g_nCount 값은
각각의 프로세스에서 증가되고 모두 1이 리턴됩니다.

즉, 처음에 말한 바와 같이 dll 내에서 static으로 선언한다고 해서
이 변수가 dll을 사용하는 프로세스 간에 공유되지는 않습니다.
그러나 변수 값을 공유하는 방법이 있습니다.

pragma directive를 사용하면 되는데
공유하고자 하는 변수를 

#pragma data_seg(".ioshare")
static int g_nCount = 0;
#pragma data_seg()

위와 같이 data_seg pragma directive 안에 넣어줍니다.
이 때 .ioshare 라는 문자열은
dll 내에 어떤 데이터 영역으로 표시되는지를 결정합니다.
지정하지 않으면 기본적으로 .data 영역에 들어가게 되죠.
(Windows PE 포맷의 기본 데이터 영역입니다.)

프로세스간 데이터 공유에 대해서는 다양한 IPC 방법이 있지만
dll을 사용해서 이렇게도 할 수 있다는 것을 기억하면 좋겠죠. ^^




반응형

 dll 로 만든 헤더를 A에서 dll 함수를 호출하면서 인자로 A 의 멤버 포인터를 넘긴다음

dll 안에서 A 의 함수를 접근하려할때 오류가 난다

원인 : dll 안에서 A 로 접근 할 수 있는 함수의 주소를 알 수 없다

+ 헤더파일에 선언된 함수 즉 inline 함수는 dllexport 할 필요가 없다

반응형

http://fendee.egloos.com/2230359



응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다VC++(2005)

원 제목: 응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
실행파일을 실행했을때, 위와같은 에러가 발생했다면,


이런 오류가 발생했을때.
물론, 갖가지 상황들이 있을 수 있으므로, 만병 통치약은 아니겠지만,
내가 접한 이 오류에 대한 분석내용을 올린다.
Visual Studio C++ 2005 가 설치되어 있는 Windows XP pro 에서 만들어진 실행파일(콘솔응용)을
아무것도 설치되지 않은(.Net Framework, C++ Runtime) Windows XP pro 에서 실행했을때,
위와같은 에러를 만나게 되었다.
여러가지 상황에서 테스트를 해보았는데,
결론은 이러하다.
여러가지 상황테스트.
.Net Framework 만 설치하고 실행시켰을때, C++ Runtime 만 설치하고 실행시켰을때, 두가지 모두 설치하고 실행시켰을때,
그러나, 모두 에러가 발생했다.
그래서, 웹서핑도 해보고, 이것저것 해본결과.
우선, 내 경우는, debug 모드로 만들어진 실행파일이었다.
아래의 위치로 들어가보면,
C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT (Visual Studio 2005의 경우)
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT (Visual Studio 2008의 경우)
내경우에는 Visual Studio 2005 이어서 이것을 기준으로 설명하겠다.
그 폴더에는 아래의 4개 파일이 있다.
Microsoft.VC80.CRT.manifest
msvcm80.dll
msvcp80.dll
msvcr80.dll
이 파일을 실행파일과 같은 폴더에 위치시키면 된다.
그런데, 문제는 그리 간단하지 않다.
위의 파일은 Release 모드로 만들어진 실행파일의 경우 필요한 파일이다.
만약, Debug 모드로 만들어진 실행파일이라면 아래의 파일이 있어야 한다.
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT (Visual Studio 2005의 경우)
폴더안에 아래의 4개 파일이 있다.
Microsoft.VC80.DebugCRT.manifest
msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
즉, 이 파일들이 없어서 에러가 났다는 것이다.
다시한번 주의하자, Debug 모드로 실행파일을 만든경우와, Release 모드로 실행파일을 만든경우 실행파일과 같이 넣어줘야할 파일이 틀리다.
보면, 디버그모드(Debug) 의 파일들에는 Debug 가 붙거나, 파일이름에 d 가 붙어 있다.
자신이 만든 실행파일이 어떤 모드에서 만들었는지 잘 기억했다가 필요한 파일로 첨부시키면 된다.
그런데, 한가지 재미있는 점은,
만약, Release 모드로 실행파일을 만들었다면, C++ Runtime 가 컴퓨터에 깔려있으면, 위의 파일들을 첨부하지 않아도 된다는 것이다.
Debug 모드로 만든경우에는 C++ Runtime 가 설치되어 있어도 에러가 난다.
그러나, 내가 만든 실행파일은, 정말 기초적인 코딩들만 들어있었다.
그런데도, C++ Runtime 를 필요로 했다면, 이건 정말 기막힐 노릇이다.
항상 프로그램을 누군가에게 주기전에 C++ Runtime 를 먼저 설치하라고 해야 한다는 말인데,
누가 그걸 설치하겠는가.
결국, 그냥 Release 모드로 만든후, dll 파일과 manifest 파일(총4개)을 실행파일과 함께 주는법 밖에는 없다는 결론이다.
정말 지극히도 단순한 코딩인데도 말이다.(Debug 모드로 만든경우에는 48kbyte 이고, Release 모드로 만든경우에는 5kbyte 밖에 안되는데도 말이다)
더 황당한것은, .Net Framework 2.0 을 설치했는데도 에러가 났다는 것이다.

그리고, 위에서 말한 폴더들을 왔다갔다 하다보면,
그 폴더만 있는게 아니고,
Debug 관련 폴더의 경우,
Microsoft.VC80.DebugMFC 폴더, Micorosft.VC80.DebugOpenMP 폴더가 있고,
Release 관련 폴더의 경우,
Microsoft.VC80.ATL 폴더, Microsoft.VC80.MFC 폴더, Microsoft.VC80.MFCLOC 폴더, Microsoft.VC80.OPENMP 폴더가 있는데,
만약, 코딩에서 MFC 를 사용했다거나, 기타 다른 것들을 사용했다면, 각 폴더안의 파일들도 같이 넣어줘야한다.
테스트결과, MFC 를 이용한 실행파일은 CRT 와 MFC 관련 폴더안에 있던 파일들을 모두 넣어줘야 에러가 나지 않았다.
하여간, 뭐가 이리 복잡한겐가.
TurboC++ 3.1(win) 에서 만든 실행파일은 기냥 돌아가더구만.
Visual Basic 의 경우에도, dll 파일을 같이 동봉해야 하는 경우가 많아 이런 에러를 만날일이 많을것이다.
듣기로는 델파이의 경우, 아예 실행파일에 dll 내용을 첨부한다던데,
물론, 그렇게 하면 실행파일의 덩치가 커지는 문제점도 있지만, 이와같이 배포시 문제점은 완벽히 해결되지 않을까?



<Visual Studio> 응용프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다. 해결방법 낙서장

2010/08/27 19:14

복사http://blog.naver.com/myrandy1/80114297241

VS2005 이후로는 제작한 프로그램을 VS가 설치되지 않은 PC에서 실행할 경우

구성이 잘못되어 응용프로그램이 실행되지 않는다는 에러가 뜨면서 실행되지 않는다.

이유는 런타임 라이브러리를 exe파일에 내재하지 않고 dll파일을 이용하여 참조하기 때문에

dll파일이 없거나 그 버젼이 다를 경우 에러가 발생된다.

몇 시간의 삽질 끝에 드디어 위의 문제를 해결할 수 있는 방법을 알아냈다.

1. 일반적으로 인터넷에 나온 방법은 다음과 같다.

C:\Program Files\Microsoft Visual Studio 9.0\VC\redist

C:\Program Files\Microsoft Visual Studio 8\VC\redist

를 보면, 재배포 정보들이 있는데

릴리즈 모드로 빌드된 프로그램은 x86, 디버그 모드로 빌드된 프로그램은 Debug_NonRedist폴더 에 들어있다.

예로 든 실행exe파일은 디버그 모드로 빌드된 프로그램이므로

C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT

C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugCRT

에 있는 파일들을 실행exe파일과 같이 배포하면 된다.

배포해야 하는 파일에는 다음과 같은 것들이 있다.

Microsoft.VC90(VC80).DebugCRT.manifest

msvcm90(80)d.dll

msvcp90(80)d.dll

msvcr90(80)d.dll

2. 하지만 실행이 되지 않았다. 보통 인터넷에 나와있는 설명에는 버전에 대한 설명이 없어서 정말 많이 해멨다...

실행파일이 요구하는 dll파일의 버젼을 알아내는 방법은 다음과 같다.

Visual Studio의 File -> Open -> File -> 실행 exe파일로 열면 메니페스트 디펜던시 정보를 얻을 수 있는데..

메니페스트 정보를 더블 클릭하면 디펜던시 정보가 hex파일로 나온다.

이를 마우스로 긁어서 메모판에 붙여 넣기를 하면 메니페스트 정보를 확인할 수 있다.

癤??xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.DebugCRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>

해당 실행파일이 필요로 하는 정보는 Microsoft.VC90.DebugCRT (9.0.21022.8), Microsoft.VC80.DebugCRT (8.0.50727.762)임을 알았다.

하지만, C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugCRT

에 있는 dll 파일들의 버젼을 확인해보니까 9.0.30729.1였다. 알고보니 dll파일의 버젼이 하나라도 다르면 실행이 안되는 것이었다.

우리가 필요한 dll버젼은 9.0.21022.8 이기 때문이 이를 찾아야 한다.

이는 C:\Windows\winsxs 에서 찾을 수 있다.

엄청나게 많은 폴더들이 있는데, 잘 찾아보면

x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.21022.8_none_96748342450f6aa2 란 이름의 폴더가 있는 것을 볼 수 있다.

이를 열어보면 우리가 찾는 9.0.21022.8 버젼의 dll파일들이 있음을 알 수 있다.

dll의 버젼이 9.0.21022.8이므로 Microsoft.VC90.DebugCRT.manifest 파일도 수정돼야 한다.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable></noInheritable>
<assemblyIdentity type="win32" name="Microsoft.VC90.DebugCRT" version="9.0.30729.1" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
....

버젼이 9.0.30729.1로 되어 있으므로 이를 9.0.21022.8로 고친다.

이렇게 해서 고친 매니페스트 파일과 런타임 dll을 실행exe파일과 함께 배포하면....

VS가 설치되지 않은 PC 에서도 잘 동작함을 볼 수 있다.

요약하면, 실행exe파일과 함께 배포해야 하는 파일은

Microsoft.VC90(VC80).DebugCRT.manifest

msvcm90(80)d.dll

msvcp90(80)d.dll

msvcr90(80)d.dll

인데, dll의 버젼과 manifest파일에 명시된 버젼과 실행 exe파일이 요구하는 dll의 버전이 모두 일치해야 한다는 것이다.


http://blog.naver.com/drvoss/20048402862

Dependency Walker : http://www.dependencywalker.com/

오늘 세미나에서 VS2008, 혹은 VS2008 feature pack에 있는 DLL들을 같이 배포 해야 하는가 라는 질문을 받았습니다. 아마도 클라이언트 PC에 2005로 컴파일된 바이너리와 2005 재배포패키지에 있는 DLL파일이 이미 배포되어 있는 상태이셨던것 같습니다.

어플리케이션은 빌드 당시에 물었었던 DLL로 링크가 됩니다. 메니페스트 파일에 이러한 내용들이 링크타임에 기술이 되게 되며,운영체제에서는 이것들을 DLL 버전등에 기반한 side by side로 관리를 합니다.

Windows 폴더에 가보시면 WinSxS 라는 폴더가 존재 하는데, 이 폴더에 보시면 같은 파일들이 각 버전별로 서로 분리가 되어 있습니다. 처음 보시는 분들은 시스템에 따라 엄청나게 많은 폴더에 있는 같은 파일에 당황스러우실 껍니다.

Side by side를 고려 하지 않으면, 보통 exe파일과 같은 폴더에 있는 DLL을 사용할 것이라 잘못 생각할 수 있습니다.

Dependency Walker exe 파일을 열면 아래와 같이 exe 파일이 물고 있는 DLL들의 목록이 보여 집니다.

여기서 F9를 눌러 보면 각 DLL 들의 Full Path가 나오게 됩니다.

아래 그림에서 보시는 것처럼 ALZip.exe은 커먼컨트롤 DLL winsxs 폴더에 저 경로의 것을 사용합니다. ALZip.exe가 있는 폴더에 다른 버전의 같은 DLL 파일을 복사해도 ALZip.exe winsxs에 있는 DLL 파일을 이용할 껍니다.

제 컴퓨터에는 아래의 두개의 경로에 같은 커먼컨트롤DLL 파일이 존재 합니다.

C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.6000.16386_none_87e0cb09378714f1

C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.6000.16386_none_5d07289e07e1d100

디펜즈에서 보시는 것 처럼 첫번째 것을 사용하고 있는데, 두번째 것을 ALZip.exe와 같은 경로로 복사를 해도 여전히 winsxs 폴더에 것을 사용하고 있음을 확인하실 수 있습니다.

exe파일의 경우 자신이 링킹될 때 참고된 DLL에 대한 메니페스트를 가지고 있고, 나중에나중에 될 때 가장 우선으로 자신이 링킹될 때 참고한 DLLside by side에서 선택합니다. 맞지 않는 DLL을 참고할경우 윈도 제어판 이벤트로그에 워닝이 남습니다.

이번 VS2008에서 side by side정보가 변경되었습니다. 따라서, dll 파일을 같이 배포해 주셔야 맞습니다.

재배포 패키지를 찾아서 배포해 주셔도 되고, 디펜즈에 있는 DLL 파일들을 복사해서 같이 복사해 주셔도 됩니다. 편한 방법을 선택하시면 됩니다.


Dependency Walker 사용법

http://notgivuphil.tistory.com/413

[쥔장]--------------------------------
전에는 idasm (visual studio.net) 을 통해서 dll을 확인했었는데, dependency walker 라는 프로그램이 있다는 사실을 알고서 이에 대한 사용방법이 있기에 스크랩을 해본다.

하지만 봐도 잘 모르겠다는... ^^;
--------------------------------------

0 - Dependency Walker?

쉽게 이야기해서 프로그래밍이 사용한 DLL 정보와 DLL에 들어있는 함수 중 사용한 함수를 보여주는 툴 (~)

1- 프로그램위치 (VS 2005기준) – 편하게 아래쪽 그림 참고

2- 그럼 실행해보자 ^0^

(1) 연결된 DLL정보를 볼 프로그래밍을 선택하기 위해 아래 아이콘을 클릭한다.

(2) 연결된 DLL 정보를 볼 프로그래밍을 선택한다

< 참고로 난 안사람은 안다는 저 흐뭇한 게임의 속을 보려고 한다 *_ *(개인적취향에 존중을)>

! 프로그래밍을 선택하고 열기를 누르자!

(3) 나온 화면

잠시 아래 Warning은 무시하자.. 그냥 대충 보니 뭔가 미확인 DLL때문에 빠진 함수가 있다는 말인 것 같다.. 참고로 난 영어 못한다. 그래서 틀린 해석일 수도 있다는 점 밝힌다. ㅡㅡㅋ;

(4) 자 사용된 DLL과 그 DLL에서 사용된 함수를 봐보자!

딱 보니 이 흐뭇한 게임에 사용된 DX9 버전은 9_32 버전이라는 점과 함께 D3DXCreateEffect 사용된것 봐서 쉐이더 HLSL를 사용했다는 것이 보이군요 후후후

(5) 자 그럼 내 프로그래밍에서 사용된 DLL는 어디에?

파란색 네모에 있는 아이콘을 누르면 바로 DLL 있는 FullPaths 가 표시 된다.

(6) 기타

* 이외에도 여러 기능들이 있는 것 같으니 직접 한번 해보시길

* Dependency Walker에 아쉬운점은 바로 아까 무시한 워닝을 출력하게 한 것처럼

MS나 공식적인 DLL가 아닌 사용자가 만든 DLL (ex, 게임엔진의 DLL)는 표씨 하지 않는다는 점이다. (어떻게 생각해보면 당연한 것 일수도 있다.) -> 응? 아닌데 나오던데?

(7) 끝으로 프로그램을 배포할 때 무슨 DLL이 사용되었고 어떤 DLL를 포함해야 할지 이 프로그램으로 먼저 파악하고

아래 같은 상황이 생겨 당황해 하지 않기 바란다..

반응형

+ Recent posts