非 MFC DLL 不依賴 MFC 類別庫,體積小、相依性低,適合跨語言、跨平台模組。本文以 VC++ 6.0 Win32 Dynamic-Link Library 專案為例,完整示範建立、導出函數/變數/類別、靜態/動態呼叫、DllMain、呼叫慣例等核心實作。
// Lib.h
#ifndef LIB_H
#define LIB_H
extern "C" __declspec(dllexport) int add(int x, int y);
#endif
// Lib.cpp
#include "Lib.h"
int add(int x, int y) { return x + y; }
#include#include typedef int(*LPADD)(int, int); int main() { HINSTANCE hDll = LoadLibrary("..\\Debug\\DllTest.dll"); if (hDll) { LPADD pAdd = (LPADD)GetProcAddress(hDll, "add"); if (pAdd) printf("%d", pAdd(2,3)); FreeLibrary(hDll); } return 0; }
流程:`LoadLibrary` 載入 → `GetProcAddress` 取函數位址 → 函數指標呼叫 → `FreeLibrary` 釋放。
; Lib.def
LIBRARY DllTest
EXPORTS
add @1
序數 `@1` 允許 `GetProcAddress(hDll, MAKEINTRESOURCE(1))` 以整數取得,比字串查找略快。
#pragma comment(lib, "DllTest.lib")
extern "C" __declspec(dllimport) int add(int x, int y);
int main() { printf("%d", add(2,3)); }
`.lib` 為導入庫,連結時嵌入 DLL 檔名與符號資訊,載入器自動完成載入與繫結。
BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID reserved) {
switch (reason) {
case DLL_PROCESS_ATTACH: printf("process attach\n"); break;
case DLL_THREAD_ATTACH: printf("thread attach\n"); break;
case DLL_THREAD_DETACH: printf("thread detach\n"); break;
case DLL_PROCESS_DETACH: printf("process detach\n"); break;
}
return TRUE;
}
驗證序列:`LoadLibrary` → `PROCESS_ATTACH` → 呼叫函數 → `FreeLibrary` → `PROCESS_DETACH`。
DLL 端聲明:
extern "C" __declspec(dllexport) int __stdcall add(int x, int y);
呼叫端函數指標:
typedef int (__stdcall *LPADD)(int, int);
若雙邊不一致(DLL 為 `__stdcall`,呼叫端漏寫 `__stdcall`),執行時拋出「Run-Time Check Failure #0 - ESP not saved」錯誤。

EXPORTS
g_var DATA
// 方式一:引用地址 (舊式)
extern int g_var;
printf("%d", *(int*)&g_var); // 必須取址解參考
// 方式二:__declspec(dllimport) 直接引用值 (推薦)
extern __declspec(dllimport) int g_var;
printf("%d", g_var);
g_var = 200; // 直接賦值
標頭檔宏切換:
#ifdef DLL_BUILD
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
class DLL_API Point {
public:
float x, y;
Point(float x=0, float y=0) : x(x), y(y) {}
};
class DLL_API Circle {
Point center;
float radius;
public:
void SetCenter(const Point& p) { center = p; }
void SetRadius(float r) { radius = r; }
float Area() { return 3.14159f * radius * radius; }
};
DLL 專案定義 `DLL_BUILD`,呼叫端直接包含標頭檔並連結 `.lib` 即可像使用本地類別一樣使用。
非 MFC DLL 開發核心在於:正確導出介面(`dllexport`/`.def`)、選擇適合架構的呼叫方式(靜態/動態)、統一呼叫慣例(`__stdcall`)、善用 `dllimport` 簡化變數/類別引用。掌握這些即可建構健壯、可跨語言呼叫的原生 Windows DLL。