LoadLibrary는 윈도우에서 사용자가 만든 DLL파일을 불러오는 함수이다
LoadLibrary를 사용하여 동적 라이브러리인 DLL파일을 불러와, 내부에 존재하는 함수를 사용할 수 있다.
아래는 DLL 사용 예제이다.
LoadLibrary로 dll파일의 주소를 적어줘, DLL을 로드하고 메모리에 매핑된 주소를 불러온다.
이후, 함수의 원형(반환값과 인자값)을 이용하여 타입을 지정한 뒤, 해당 타입을 이용하여 함수를 불러올 수 있다. (함수는 기본적으로 주소를 가지고 있는 포인터변수이다. 이에 괄호를 통해 인자를 주거나, 인자를 주지 않으면 직접 실행하도록 되는것이다.)
함수의 주소를 받는것은 GetProcAddress를 이용해 받을 수 있다. 인자로 모듈주소와 모듈이름을 주면 인자를 반환한다. 모듈 이름을 모를경우 DLL정보를 보는 프로그램을 이용할 수 있다.
함수의 이름을 알 수 없는경우 함수 내부 번호를 이용해 MAKEINTRESOURCE(ordinal)을 대신 넣어주면 되는 것 같다. 확인필요
추가적으로 검색하다 알게 된 내용인데 다음과 같은 방법으로도 함수를 불러올 수 있는 모양이다.
그리고 과거에 만들었던 코드에서 찾아보니 다음과 같은 코드도 유효했다.
위의 두 경우에도 결과값은 잘 나온다.
추가적으로 인자에 괴상한 값이나 콜백함수를 줘야할 때는 다음과 같은 방법을 사용하면 된다.
다음은 소스코드이다.
#include <iostream> // __stdcall은 함수를 끝낼 때 스택정리를 하지 않는것, __cdecl방식은 함수를 끝낼 때 스택정리를 하는것
#include <windows.h>
int main (int argc, char **argv) {
HMODULE hmodule = LoadLibrary("makeDll.dll"); // DLL을 로드한다.
if (hmodule == nullptr) { // 만약 제대로 로드되지 않았으면 종료한다.
std::cout << "DLL 로드에 실패하였습니다." << std::endl;
return 1;
}
// 불러온 라이브러리에서 "add"함수를 찾아 주소를 가져온다.
// 함수에 대한 타입을 지정해준다. (반환값과 인자값때문에 반드시 지정해줘야한다.)
typedef int (*MyType1)(int, int); // 반환형이 int인, 인자를 int, int로 주는 함수의 타입이다.
MyType1 add = (MyType1)GetProcAddress(hmodule, "add");
int result = add(10, 20); // 불러온 함수를 다음과 같은 방법으로 사용하면 된다.
std::cout << "result is " << result << std::endl;
PVOID AddPointer = reinterpret_cast<void*>(GetProcAddress(hmodule, "add")); // getProcAddress는 단순히 주소를 반환하는것이기 때문에 해당 코드처럼 포인터를 저장해놔도 된다.
// (PVOID는 void*이다.)
int(__cdecl* add2)(int, int) = (int(__cdecl*)(int, int))AddPointer; // __cdecl*방식으로 해당 포인터를 받아 할당하는 방법도 있다.
result = add2(30, 40);
std::cout << "result is " << result << std::endl;
typedef int (__stdcall *MyType2)(int, int); // __stdcall방식으로 타입을 지정해도 된다.
MyType2 add3 = (MyType1)GetProcAddress(hmodule, "add");
result = add(5, 10); // 그리고 이런 방식으로 호출한것은 __cdecl방법으로 적용되는진 모르겠다. 디버깅이 필요하다.
std::cout << "result is " << result << std::endl;
return 0;
}
__stdcall과 __cdecl에 대한것을 오랫만에 보아 찾아보았다. __stdcall은 표준 호출이고, __cdecl은 c 선언이라는 듯 같다.