首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 動態載入/卸載非託管 DLL:以 LoadLibrary/GetProcAddress/FreeLibrary 實現熱重載

     編輯:關於C#

場景痛點:靜態變數無法重置

遇過這樣的需求:第三方 C++ DLL 內部有個靜態計數器,每次呼叫遞增。業務要求在特定時刻將計數器歸零,但 DLL 原始碼不可改。C# 直接 DllImport 只能載入一次,無法像 AppDomain 那樣卸載重載。解法:繞過 .NET 載入器,直接呼叫 Windows API 手動管理模組生命週期。

核心 API 簽名

[DllImport("kernel32", EntryPoint = "LoadLibrary", SetLastError = true)]
static extern IntPtr LoadLibrary(string lpLibName);

[DllImport("kernel32", EntryPoint = "GetProcAddress", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

[DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
static extern bool FreeLibrary(IntPtr hModule);

取得函數指標並呼叫:IL 硬碼委派

拿到 GetProcAddress 回傳的函數指標 IntPtr pfn 後,C# 無法直接像 C++ 那樣轉型呼叫。靈感來自 calli IL 指令:寫一個極小的 IL 組件 Wrapper.il,定義靜態方法接受 native int 並 calli unmanaged stdcall int32(),編譯成 DLL 後在 C# 專案參考即可。

.assembly extern mscorlib {}
.assembly Wrapper {}
.class public Wrapper {
    .method public static int32 SomeMethod(native int pfn) {
        .maxstack 2
        .locals (int32 V_0)
        ldarg.0
        calli unmanaged stdcall int32()
        stloc.0
        ldloc.0
        ret
    }
}

C# 呼叫端:

IntPtr hMod = LoadLibrary("ADll.dll");
IntPtr pfn = GetProcAddress(hMod, "GetValue");
int result = Wrapper.SomeMethod(pfn); // 成功呼叫!
MessageBox.Show(result.ToString());
FreeLibrary(hMod); // 卸載,下次 LoadLibrary 會重新初始化靜態變數

關鍵優勢

  • 完全控制 DLL 載入/卸載時機,解決靜態狀態重置難題。
  • 無需修改原廠 DLL,亦無需建立額外 AppDomain 隔離。
  • IL Wrapper 僅十幾行,編譯一次永久複用。

注意:須確保呼叫慣例(stdcall/cdecl)與 DLL 導出一致,否則堆疊會損毀。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved