Windows DLL内の関数を呼び出す方法

## 初めに

### DLLの書き方
__declspec(dllexport)を書かないと外部からこの関数を呼び出せない。
```mylib.c
#include <windows.h>

__declspec(dllexport) int add_numbers(int a, int b) {
    return a + b;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    return TRUE;
}
```

### 呼び出し部分
<details>
<summary>main.c全体</summary>

```main.c
#include <windows.h>

typedef int (*AddFunc)(int, int);
int g_result = 0; // 計算結果を保持する広域変数

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            
            // 背景を塗りつぶし
            RECT rect;
            GetClientRect(hWnd, &rect);
            FillRect(hdc, &rect, GetSysColorBrush(COLOR_WINDOW));
            
            // 計算結果を表示
            char buf[100];
            sprintf(buf, "5 + 3 = %d", g_result);
            TextOut(hdc, 50, 50, buf, strlen(buf));
            
            EndPaint(hWnd, &ps);
            break;
        }
        
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
            
        default:
            return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow) {
    // DLLの読み込み
    HINSTANCE hDll = LoadLibrary("mylib.dll");
    if (!hDll) return 1;
    
    AddFunc add_numbers = (AddFunc)GetProcAddress(hDll, "add_numbers");
    if (!add_numbers) {
        FreeLibrary(hDll);
        return 1;
    }
    
    // 計算実行
    g_result = add_numbers(5, 3);
    
    // ウィンドウクラス登録
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszClassName = "MainWindow";
    
    if (!RegisterClass(&wc)) {
        FreeLibrary(hDll);
        return 1;
    }
    
    // ウィンドウ作成
    HWND hWnd = CreateWindow(
        "MainWindow",
        "DLL GUI Demo",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        400, 300,
        NULL, NULL, hInstance, NULL);
        
    if (!hWnd) {
        FreeLibrary(hDll);
        return 1;
    }
    
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    
    // メッセージループ
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    FreeLibrary(hDll);
    return (int)msg.wParam;
}
```
</details>

```DLLの呼び出し部分.c
    // DLLの読み込み
    HINSTANCE hDll = LoadLibrary("mylib.dll");
    if (!hDll) return 1;

    //関数アドレス取得
    AddFunc add_numbers = (AddFunc)GetProcAddress(hDll, "add_numbers");
    if (!add_numbers) {// 関数取得に失敗
        FreeLibrary(hDll);//解放
        return 1;
    }
    
    // 計算実行
    g_result = add_numbers(5, 3);
```

## 動作確認

### コンパイル方法
```
gcc -shared -o mylib.dll mylib.c
gcc -o main.exe main.c -lgdi32
```

### 動作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4054974/c3f66906-4d9a-48d6-b2fa-8a2b0fe3d968.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4054974/7e2f320d-1b5c-42f3-b697-52c6d26d605b.png)

## 動作環境

windows7 Version6.1.7601
GCC-6.3.0-1

（帰省中につき一時的に昔のパソコンを使用している。windows7が懐かしい。。。）