제목은 거창하나 간단한 설명입니다.
아주 세밀한 설명은 다른곳에서 도움 받으시길 원하며, 처음 라이브러리를 접하시는 분을 위해, 그리고 자주 까먹는 저를 위해 이렇게 글로 작성해둡니다.. -.-;;;
라이브러리 사용만 해봤지 한번도 만들어 본적이 없었는데..
갑작스레 회사프로그램을 통채로 라이브러리화시키는 일을 맡아버려서 얕게 나마 알게 되었습니다.
참고로 급조된 지식입니다 -_-;
일단 쉽게 설명하면, 라이브러리란 블랙박스와 같은 형태입니다.
그 안을 들여다 볼수가 없고 export가 허락된 함수나 데이터만 접근할수 있는 형태의 파일을 말합니다.
개발에 용의하고, 모듈화의 적합하기 때문이라고 하지만..
역시 궁극적인 목표는 자신의 기술을 외부에 유출시키지 않는 방법이 아닐까 싶습니다.
예를 들면 mp3를 재생시키는 코딩을 라이브러리화 시켜서 배포하면 누구나 다 mp3재생을 할수 있지만,
그안을 들여다 볼수 없기에 절대 mp3 재생을 위한 코딩이 어떻게 되는지 알수 없습니다.
라이브러리는 정적 라이브러리와 동적 라이브러리가 있습니다.
쉽게 설명하면, 정적 라이브러리는 LIB라는 형태로 프로그램을 만들때 그 lib 파일 자체를 컴파일시에 포함해서 코딩해야합니다.
따라서 프로그램 용량이 커지고, 라이브러리 내용만 수정해야 한다해도 다시 프로그램 전체를 컴파일 해야하는 단점이 있습니다.
동적라이브러리는 DLL형태입니다.
DLL형태는 프로그램을 컴파일할때 없어도 됩니다. 단지 실행할때 dll파일이 함께 있음으로써 사용되어지기에,
프로그램 용량이 적어지고, 라이브러리 내용만 수정되어야 할 일이 있다면 라이브러리만 따로 컴파일하면 되기에 업데이트등에 용이합니다.
이스트소프트사의 알집의 경우 폴더를 살펴보면, 수많은 dll 파일들이 있는데 각각 dll들은 독립된 라이브러리입니다.
만약 알집이 lib를 이용했다면, dll이 없고, 달랑 실행파일 하나와 그외 기타 파일만 존재했을것입니다.
LIB같은 형태는 꼭 숨기고 싶은 라이브러리를 만들때, 혹은 업데이트할 일이 없는 형태일때 만드는것이 좋은것같습니다.
다음은 실질적인 만드는 부분입니다.
저는 vc8 2005로 넘어가게 되서 2005를 기준으로 설명합니다.(사실 vc6과 별 차이없습니다 -.-;)
참고로 라이브러리를 만들때는 라이브러리 프로젝트 외에, 그 라이브러리를 사용하는 프로젝트를 동시에 만들어서,
컴파일하면 라이브러리 먼저 컴파일한뒤, 그 라이브러리를 적용하는 프로그램을 컴파일하게 하면 개발할때 편합니다.
프로젝트를 따로 두면 하나 컴파일하고, 또 그걸 적용해보는 프로그램 컴파일하고, 시간도 시간이지만 엄청 귀찮습니다.
그리고 라이브러리를 import할때는 반드시 경로에 주의해야합니다.
정적 라이브러리 만드는 방법 및, 사용방법
vc6의 경우 프로젝트 첨부할때 보면 맨밑에 Win32 Static Library가 있습니다.
vc8의 경우는 Win32탭에 Win32 프로젝트를 선택하시면 됩니다.
(클릭해서 밑에 설명란 보면, dll 또는 정적 라이브러리를 만드는 프로젝트라고 써있습니다.두개가 2005에서는 합쳐진듯합니다)
선택을 하신뒤 보면, DLL이든 정적라이브러리든 다시 선택할수 있으며, MFC를 정적으로 링크할것이냐도 선택할수 있는데..
이건 사실 별 문제가 아닙니다. 언제든 MFC야 링크하게 바꿀수도 없앨수도 있으니 신경 안쓰셔도 됩니다.
여기서 정적라이브러리를 선택 하시면 프로젝트가 만들어집니다.
솔루션 탐색기를 보시면 stdafx.h와 cpp만 있을것입니다.
이제는 코딩만 하시고, 바깥에서 쓸수있게 export 설정만 하시면 됩니다.
저같은 경우는 코딩의 용이함을 위해 클래스로 만들어서 코딩합니다.
(참고로 굳이 그러실 필요는 없습니다. 코딩스타일은 개인차이고, 또한 알고리즘에 따라 다른거라..)
클래스뷰를 보시면 프로젝트명과 달랑 매크로및 상수만 있는데 여기에 클래스를 추가해줍니다.
클래스명은 반드시 현재 프로젝트명입니다. 그래야 프로젝트명.h와 cpp가 생겨납니다.
클래스로 안만드실 분은 그냥 프로젝트명.cpp만 있어도 됩니다.
그다음 필요한것은 프로젝트명.def 파일을 추가해주어야 합니다. 이 파일은 밖으로 유출시킬 함수를 설정해주는것으로
반드시 필요합니다.(이건 마지막에 하면 됩니다.)
중요한건, export 할수 있는 함수는 전역함수라는것입니다. (정확한건 아닙니다 -.-; 아무래도 급조해서 만들어본거라..)
하지만, 멤버함수야 전역함수에서 가져다 쓸수 있으니 별 문제는 아닙니다
뒤에 특정 클래스의 멤버함수에 접근 하는 간단한 방법도 적어두겠습니다.
일단, 아주 쉬운 예제를 들어보겠습니다
일단 클래스뷰에 프로젝트명 부분에 오른쪽 마우스 클릭하시고 속성을 보시면,
구성속성->일반-> 부분에 정적라이브러리(.Lib)가 선택되어 있는지 확인하셔야 합니다.
그다음,
프로젝트명.h에
void Test();를 선언해준후
cpp에는 (당연히 최상단부에 #include "프로젝트명.h"가 있어야 합니다)
void Test()
{
MessageBox(L"이 메시지박스는 lib내부 함수에서 호출되었습니다", L"", MB_OK);
}
라고 만들었습니다
그후 프로젝트명.def에
EXPORTS
;
Test @1
이라고 코딩합니다.
여기서 test는 밖으로 유출할 함수명이며, @1은 번호입니다.
두번째 유출 함수는 @2, 세번째는 @3 이런식으로 작성해주면 됩니다.
컴파일하면 프로젝트명.lib가 만들어집니다.
그다음 새 프로젝트를 만들어서 테스트를 해보면 됩니다.
새 프로젝트에서 정적라이브러리를 위해 필요한 것은 컴파일된 lib파일과 h파일입니다.
h 파일에는 보통 해당 lib에 접근해서 쓸수 있는 함수가 무엇무엇이 있는지 알려줍니다.
예를 들면 void Test();이런식으로 test 함수를 import할수 있음을 알려줍니다.
(h파일이 반드시 필요한지는 잘 모르겠습니다 한번도 빼본적이 없어서 -_-;)
보통 lib와 같이 포함되는 h파일 작성은 위와 같은 코딩이였다면,
void Test(); 이것 하나만으로 충분합니다. lib 안에 import 할수 없는 함수라면 적을 필요없습니다.
즉, lib 프로젝트할때 쓴 lib프로젝트명.h에서 쓸데없는거(import불가능한것들) 다 지우고 가져다가 쓰시면 됩니다.
위에 예제를 계속 이어간다면,
프로젝트 속성에 구성속성->라이브러리관리자-> 일반에 보시면 추가종속성이 있습니다.
그곳에 반드시 lib프로젝트명.lib를 추가해주세요
새프로젝트명.h에는 #include "lib프로젝트명.h" 선언해주시구요
그다음에는 그냥 Test();
호출만으로 lib안에 Test()가 호출됨을 알수 있습니다.
동적 라이브러리 만드는 방법, 및 사용방법
vc6의 경우 프로젝트 첨부할때 보면 맨밑에 Win32 Dinamic-Link Library가 있습니다.
vc8의 경우는 Win32탭에 Win32 프로젝트를 선택하시면 됩니다. (정적라이브러리와 동일합니다)
역시 2005를 기준으로 하며, 위에 설명이 있으니 간단하게만 설명하겠습니다.(2005나 vc6이나 사실 별차이 없습니다)
프로젝트 속성을 보시면, 구성속성->일반-> 부분에 동적라이브러리(.Dll)로 바꾸어주셔야 합니다.
정적라이브러리와 마찬가지로, 해당프로젝트명.cpp가 기본 base입니다.
해당프로젝트명.h는 역시 선택사항입니다.
다른점은 밖으로 export할 전역 함수들의 선언인데..
동적 라이브러리는 extern "C" __declspec(dllexport)를 앞에 붙여줍니다.
예를 들어 프로젝트명과동일한 클래스를 추가한후,
프로젝트명.h에는
extern "C" __declspec(dllexport) void Test();
라고 선언해주고,
프로젝트명.cpp에는
__declspec(dllexport) void Test()
{
MessageBox(L"이 메시지박스는 lib내부 함수에서 호출되었습니다", L"", MB_OK);
}
이렇게 함수를 만들어줍니다.
정적라이브러리와 마찬가지로 전역함수이며,
특정 클래스에 접근하는 방식 또한 뒤에 쓴것처럼 하시면 됩니다.
문제는 def파일인데..
만들지 않아도 상관없습니다
(밑에 EXPORT 하는 방법은 따로 있으나, 지금 이대로 해도 상관없습니다.)
이제 다른 프로젝트에서 불러오는 일만 남았는데..
불러오는 방식은 implict와 explicit 두가지 방법이 있습니다.
두가지 방법의 차이는
implicit 링킹은 프로그램이 시작되면서 해당 dll을 바로 로드 하는 방식으로, h파일, lib 파일 모두 필요합니다.
처음부터 제가 dll을 만들기 시작한 업데이트성의 용이를 위해서 h파일과 lib파일은 없어야할 존재이기에 이 방법은 해보지 않았습니다.
explicit 링킹은 단지 dll 파일 하나만으로 호출 가능한 방법입니다.
다음은 explicit 방법을 사용해서 dll만으로 import 하는 방법입니다.
dll을 사용하게 될 새 프로젝트를 하나 만드시고, lib와는 다르게 프로젝트의 추가종속성에 dll 파일을 넣으시지 않아도 됩니다.
(확실하진 않지만 아마 넣으면 에러가 나오던가 그랬던걸로 기억합니다. -_-;;; 확실한건 안넣으셔도 된다는것..)
필요한것은 단지 dll을 호출하는것입니다.
호출할때는 해당 dll을 로드하고 함수를 사용하면 됩니다.
예)
HINSTANCE hDll; //dll파일을 로드할 인스턴스핸들입니다.
hDll = LoadLibrary("해당파일.dll"); //로드합니다.
typedef void (*TestFunc)(); //불러올 Test파일이 어떤 형식인지 알고 반드시 같은 형식으로 typedef로 설정합니다.
//혹시 test함수가 int test(int num);이라면 typedef int (*TestFunc)(int num);으로 해주어야합니다.
TestFunc Test; //test()를 import시키기 위한 설정입니다.
Test = (TestFunc)GetProcAddress(hDll,"Test"); //test함수를 얻어옵니다. GetProcAddress의 두번째인자는 해당함수명입니다.
Test(); //import한 함수를 실행합니다.(dll내의 함수가 직접 호출)위와같은 dll을 만들었다면 메시지박스가 호출되어질것입니다
FreeLibrary(hDll); //사용후에는 반드시 닫아주셔야 합니다
가장 중요한것은..loadLibrary해줄때 경로가 틀리면 에러가 난다는 점입니다.
제가 배운 서적에는 hDll == NULL 이라면 dll이 로드 안된거라고 나왔는데..
제가 해보니 로드 안되었는데도 NULL이 아니라서 에러때문에 고생했습니다 -_-;; 저는 2005에서 해서 다른건지는 잘 모르겠습니다.
여기까지만 하셔도 dll의 기능은 충분히 수행할수 있습니다
다음은 데이터변수도 공유방법과, EXPORT도 설정방법입니다. (저는 사용하지 않았습니다.)
공유 데이터 정의할때는
#pragma data_seg("SHARDATA")
int 공유할 변수;
#pragma data_seg()
라고 해주고,
def 파일에
SECTIONS
SHARDATA Read Write Shared
를 추가합니다.
EXPORT 방법은 EXPORT할 함수 선언은
void CALLBACK Test();
라고 선언해주고
def에는
EXPORT
Test @1
로 해줍니다. 역시 @1는 함수번호로 그다음 함수는 @2 등으로 순차적으로 부여해줍니다.
정적 라이브러리 -> 동적라이브러리 변경하는 방법
(반대 경우도 마찬가지)
저는 MFC DLL 프로젝트로 만들어 보지 않고 Win32 DLL프로젝트나 LIB으로만 만들어 봐서 MFC DLL 프로젝트에서 바꾸는 법은
잘모르겠습니다 -.-; 일단 해보지 않은거라...
그치만, Win32에서는 간단합니다.
위에 보시면 아시겠지만, 정적라이브러리와 동적 라이브러리 만들때 차이는 export 시키는 함수 선언등 약간의 차이뿐이라..
그냥 위에 글 보시면서 함수 선언부분이랑 프로젝트 속성->구성속성->일반 부분 바꿔주시고, def부분도 바꾸시면 됩니다.
저도 처음에 lib로 만들었다가 dll로 필요했다는걸 알고 lib 상태에서 바로 dll로 바꿔 만들었습니다.
그리고 그걸 바꿔주는 프로그램도 있다 그러는데.. 큰 차이가 없어서 저는 그냥 코딩으로 바꿔주었습니다.
MFC 링크 없애는 법, 추가하는 법
초반에 프로젝트 생성할때, mfc 링크를 선택하는데, 이부분은 단지 프로젝트속성에서 mfc 링크로 바꾼다고 어떻게 되는 부분이 아닙니다. 그러나 MFC 링크는 없애는 법과 추가하는 법이 모두 간단합니다.
여기에 코딩하면 좀 길어져서 아주 쉬운 방법만 알려드리겠습니다.
처음 라이브러리 프로젝트 만들때 MFC 링크를 선택하느냐 안하느냐에 따라 stdafx.h의 내용이 달라집니다.
즉, 아무 프로젝트나 새로 만들어서 mfc 링크를 해보고, 안해보고 두개 만들어보면 됩니다.
mfc를 없애고 싶으면, 추가 안한 프로젝트의 stdafx.h 내용으로 바꾸면 되고, 추가하고 싶을때는 그 반대로 하면 됩니다.
전역함수에서 특정 클래스의 멤버함수에 접근 하는 방법
저는 클래스의 멤버함수를 직접 export 시킬수 있는지는 솔직히 잘 모르겠습니다.
그러나 전역함수에서 언제든 연결할수 있으니 별 문제는 없는것 같습니다.
간단한 라이브러리라면 모를까..
보통 클래스도 많이 들어간 덩치 있는 라이브러리를 만든다면 반드시 클래스에 접근을 해야합니다.
뭐 예를 들어 전역함수 몇개를 export 시켜두고 그 전역함수를 호출하면 그 전역함수내에서 클래스 멤버함수나 쓰레드 전역함수등에 접근 하는 방식을 사용하면 됩니다.
방법은 간단합니다.
라이브러리를 만드실때 원하는 클래스가 CTest라는 클래스라면,
cpp 파일에 전역변수로 CTest g_Test;라고 선언해줍니다
전역 함수내에서 CTest클래스에 접근할때
g_Test.접근원하는멤버변수나 함수;를 사용하시면 됩니다.
그리고, 라이브러리 외에 보통 프로젝트에서 전역 함수네서 변수를 쓰는 방법은 약간 다릅니다
CTest라는 클래스의 멤버에 접근하고 싶다면
CTest g_pTest;라고 포인터 전역변수를 설정하고,
해당 클래스 생성자 부분에 g_pTest = this;라고 해준후
전역함수내에서 g_pTest->원하는멤버;
이런식으로 상요해주시면 됩니다.
혹시 모르시는 분을 위해..
참고로 생성자는 생성될때 제일먼저 호출되는 함수로
C클래스명::C클래스명(void) //생성자함수
{
g_pTest = this;//이런식으로 들어가면 됩니다.
}
이런식으로 되어있습니다. (클래스 추가를 통해 만들면 자동으로 만들어집니다.)
예전에는 이런 방법을 몰라서 전역함수로 핸들을 직접 넘겨주고 그랬는데 --; 알고보니 참 간단하더군요
[출처] 동적 라이브러리 만들기|작성자 ylovey0
'프로그래밍 > VC++ 개발 코딩' 카테고리의 다른 글
JPG resouce 등록하고 사용하기 (0) | 2014.01.17 |
---|---|
VC++ PG_SEND (0) | 2014.01.17 |
메모리 정적/동적 할당하여보자 (0) | 2014.01.17 |
현재시간구하기 & 지난시간구하기 (0) | 2014.01.17 |
마우스 커서 모양 바꾸기 (0) | 2014.01.17 |