C/C++ LoadLibrary

Posted by : on

Category :


LoadLibrary는 윈도우에서 사용자가 만든 DLL파일을 불러오는 함수이다

LoadLibrary를 사용하여 동적 라이브러리인 DLL파일을 불러와, 내부에 존재하는 함수를 사용할 수 있다.

아래는 DLL 사용 예제이다.

DLL을 불러와 GetProcAddress를 이용하여 함수를 불러오는 예시

LoadLibrary로 dll파일의 주소를 적어줘, DLL을 로드하고 메모리에 매핑된 주소를 불러온다.

이후, 함수의 원형(반환값과 인자값)을 이용하여 타입을 지정한 뒤, 해당 타입을 이용하여 함수를 불러올 수 있다. (함수는 기본적으로 주소를 가지고 있는 포인터변수이다. 이에 괄호를 통해 인자를 주거나, 인자를 주지 않으면 직접 실행하도록 되는것이다.)

함수의 주소를 받는것은 GetProcAddress를 이용해 받을 수 있다. 인자로 모듈주소와 모듈이름을 주면 인자를 반환한다. 모듈 이름을 모를경우 DLL정보를 보는 프로그램을 이용할 수 있다.

함수의 이름을 알 수 없는경우 함수 내부 번호를 이용해 MAKEINTRESOURCE(ordinal)을 대신 넣어주면 되는 것 같다. 확인필요

DLL을 사용한 함수의 결과값

추가적으로 검색하다 알게 된 내용인데 다음과 같은 방법으로도 함수를 불러올 수 있는 모양이다.

typedef 없이 함수를 지정하는 방법

그리고 과거에 만들었던 코드에서 찾아보니 다음과 같은 코드도 유효했다.

__stdcall을 이용한 함수호출

위의 두 경우에도 결과값은 잘 나온다.

위의 두 코드에 대한 결과값

추가적으로 인자에 괴상한 값이나 콜백함수를 줘야할 때는 다음과 같은 방법을 사용하면 된다.

과거에 작성했던 코드

다음은 소스코드이다.

#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 선언이라는 듯 같다.


Useful Links