我正在嘗試創建幾個具有不同實作但符號匯出一致的 Win32 64 位 DLL(Windows 10)。這樣做的目的是在構建時與任何一個鏈接,但在部署時可以選擇安裝任一 DLL 并正確運行。我已經在 Linux 上直接實作了這一點,在那里我對運行時鏈接更加熟悉和熟悉。但是在 Windows 上,我還沒有做到這一點,我想知道這是否可能。我正在嘗試使用 VS2010 和 VS2019。
假設我有兩個庫 blah_legacy.dll 和 blah_modern.dll。它們都匯出 6 個符號,它們是使用庫的介面,例如 blah_open、blah_read、blah_write、blah_close、blah_control、blah_status。
我可以鏈接匯入庫以實作 blah 實作和呼叫每個符號的測驗程式加載并使用相應的 blah DLL 正確執行。
但是,我還不能在運行時切換 DLL。例如,如果我將其重命名為 blah-legacy.dll,我是否真的可以與 blah-legacy.lib 鏈接,然后與 blah-modern.dll 一起運行?(或相反亦然。)
我已經解決了基本的檔案命名問題,并確保實際上可以找到所需的 DLL。我仍然發現應用程式無法啟動 (0x22)。
我在 DLL 上使用了“objdump -xs”,并注意到符號的順序和它們的序數是不同的。所以我創建了一個 .def 檔案并確保匯出的符號在數字、名稱和序數上匹配。仍然沒有 - 發生同樣的錯誤。
我顯然還沒有弄清楚這一點,希望得到一些指導。這真的可能嗎?我從哪里開始尋找(使用哪些工具)來確定下一步要采取的步驟。
uj5u.com熱心網友回復:
是的。
我不怎么使用 Visual Studio,但是如果您使用MSYS2并安裝一些 MinGW 包并更新它們,這種情況就會一直發生。
這就是我的意思:MSYS2 是 Windows 的開源軟體發行版,除其他外,它提供了一堆本機 Windows 軟體包。包管理器 ( pacman) 讓您選擇系統中的包,它會下載由 MSYS2 開發人員創建的 DLL 和 EXE。當 MSYS2 開發人員更新庫時,您可以下載更新的庫包,所有其他使用該庫的包將自動開始使用新的 DLL。通常沒有問題,因為新庫版本將與舊庫版本 ABI 兼容。
你不是需要使用LoadLibrary或以其他方式弄亂你的源代碼; 聯結器和作業系統應該能夠為您解決這個問題。
例子
這是我與 MSYS2 放在一起的一個最小示例,展示了它是如何作業的。
該檔案foo_legacy.c代表您的舊 DLL。我添加了一些額外的符號,這樣它就不會與現代 DLL 太相似了。
__declspec(dllexport) int eoo() {
return 0;
}
__declspec(dllexport) const char * foo_name() {
return "legacy";
}
__declspec(dllexport) int foo_version() {
return 1;
}
__declspec(dllexport) int goo() {
return 0;
}
該檔案foo_modern.c代表現代實作:
__declspec(dllexport) const char * foo_name(void);
__declspec(dllexport) int foo_version(void);
int foo_version() {
return 2;
}
const char * foo_name() {
return "modern";
}
該檔案main.c表示使用fooAPI的應用程式:
#include <stdio.h>
__declspec(dllimport) const char * foo_name(void);
__declspec(dllimport) int foo_version(void);
int main()
{
printf("%s %d\n", foo_name(), foo_version());
}
我的 build.sh 檔案是一個 Bash 腳本,用于構建和測驗所有內容:
#!/usr/bin/bash
set -uex
gcc -Wall foo_legacy.c -shared -o foo_legacy.dll
gcc -Wall foo_modern.c -shared -o foo_modern.dll
gcc -Wall -c main.c -I. -o main.o
gcc main.o foo_legacy.dll -o main.exe
./main.exe # output: "legacy 1"
mv foo_modern.dll foo_legacy.dll
./main.exe # output: "modern 2"
rm foo_legacy.dll
./main.exe # fails because foo_legacy.dll is not found
構建腳本運行了main.exe三個不同的時間,表明它可以使用舊版 DLL,也可以使用現代 DLL,也可以失敗,具體取決于foo_legacy.dll.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/373552.html
