:解決只生成DLL不生成LIB文件的完整指南)
1. 項(xiàng)目概述與問(wèn)題定位在Visual Studio 2022環(huán)境下開發(fā)C/C動(dòng)態(tài)鏈接庫(kù)DLL對(duì)于很多從靜態(tài)庫(kù)轉(zhuǎn)向動(dòng)態(tài)庫(kù)或者從其他開發(fā)環(huán)境遷移過(guò)來(lái)的朋友來(lái)說(shuō)一個(gè)非常典型且令人困惑的問(wèn)題就是為什么我的項(xiàng)目明明編譯成功了在輸出目錄里也看到了生成的.dll文件但就是找不到對(duì)應(yīng)的.lib文件沒有這個(gè).lib文件其他應(yīng)用程序就無(wú)法通過(guò)“隱式鏈接”的方式使用你的DLL只能退而求其次使用相對(duì)復(fù)雜的“顯式鏈接”運(yùn)行時(shí)加載。這就像你造好了一棟功能齊全的房子DLL卻把唯一的門鑰匙LIB給弄丟了外面的人知道房子在哪但就是進(jìn)不去。我自己在帶團(tuán)隊(duì)和做項(xiàng)目遷移時(shí)就多次踩過(guò)這個(gè)坑尤其是在升級(jí)到VS2022后一些默認(rèn)的項(xiàng)目配置和舊教程存在差異更容易導(dǎo)致新手掉進(jìn)這個(gè)陷阱。這個(gè)LIB文件專業(yè)術(shù)語(yǔ)叫“導(dǎo)入庫(kù)”它本身并不包含函數(shù)的具體實(shí)現(xiàn)代碼而是一個(gè)“地址簿”或“跳轉(zhuǎn)表”里面記錄了DLL中所有導(dǎo)出函數(shù)的名字和序號(hào)。鏈接器在編譯你的客戶端應(yīng)用程序時(shí)需要這個(gè)LIB文件來(lái)解析那些來(lái)自DLL的函數(shù)調(diào)用告訴程序“這個(gè)函數(shù)在某某DLL里你運(yùn)行的時(shí)候去那里找?!?如果缺失了LIB鏈接階段就會(huì)直接報(bào)錯(cuò)提示“無(wú)法解析的外部符號(hào)”。所以當(dāng)你發(fā)現(xiàn)VS2022只生成了DLL而沒有生成LIB時(shí)這通常不是一個(gè)Bug而是一個(gè)配置問(wèn)題。核心原因往往出在兩個(gè)方面一是項(xiàng)目類型或配置屬性設(shè)置不當(dāng)導(dǎo)致編譯器沒有生成導(dǎo)出符號(hào)信息二是代碼層面沒有正確地聲明導(dǎo)出函數(shù)或類。接下來(lái)我們就從這兩個(gè)核心維度把問(wèn)題掰開揉碎了講清楚并提供一套從檢查到解決的完整操作流程。2. 核心原理DLL、LIB與導(dǎo)出機(jī)制深度解析要徹底解決問(wèn)題必須先理解背后的機(jī)制。很多人對(duì)DLL和LIB的關(guān)系一知半解這里我用一個(gè)更生活化的比喻來(lái)解釋。想象一下DLL是一個(gè)裝滿工具函數(shù)的共享工具箱放在一個(gè)公共倉(cāng)庫(kù)里。LIB文件呢它不是另一套工具而是這個(gè)工具箱的“工具清單”和“倉(cāng)庫(kù)地圖”。當(dāng)你自己的項(xiàng)目客戶端程序需要使用“扳手”這個(gè)工具時(shí)你的編譯過(guò)程分為兩步編譯Compile檢查你的代碼語(yǔ)法看到你調(diào)用了UseWrench()函數(shù)它知道有這么一個(gè)函數(shù)聲明但不知道具體在哪。鏈接Link鏈接器登場(chǎng)它需要把“調(diào)用UseWrench()”這行代碼和UseWrench()函數(shù)真正的機(jī)器代碼連接起來(lái)。這時(shí)鏈接器會(huì)去查閱你提供的“工具清單”LIB文件。LIB文件告訴鏈接器“UseWrench()這個(gè)工具的實(shí)現(xiàn)在MyTools.dll這個(gè)工具箱里它的內(nèi)部編號(hào)是#2。” 于是鏈接器在你的程序里生成一條記錄“當(dāng)需要UseWrench時(shí)請(qǐng)去加載MyTools.dll并調(diào)用其中的第2號(hào)工具?!?這個(gè)記錄就保存在你最終生成的.exe文件中。程序運(yùn)行時(shí)操作系統(tǒng)加載你的.exe看到這條記錄就會(huì)去找到并加載MyTools.dll然后根據(jù)編號(hào)#2找到正確的函數(shù)地址完成調(diào)用。這就是“隱式鏈接”。那么為什么有時(shí)候沒有LIB文件呢問(wèn)題就出在“工具清單”的生成上。Visual Studio生成LIB文件依賴于一個(gè)關(guān)鍵信息導(dǎo)出符號(hào)列表。這個(gè)列表需要通過(guò)以下兩種方式之一告訴編譯器2.1 方式一使用模塊定義文件.def這是一個(gè)純文本文件明確列出了DLL要導(dǎo)出的所有函數(shù)名有時(shí)還包括序號(hào)。鏈接器看到這個(gè)文件就會(huì)嚴(yán)格按照列表來(lái)生成LIB和DLL的導(dǎo)出表。這是最古老但也最明確的方式特別適合純C接口或者需要精確控制導(dǎo)出函數(shù)序號(hào)的場(chǎng)景。2.2 方式二在代碼中使用__declspec(dllexport)關(guān)鍵字這是C中更常用的方式。你在聲明函數(shù)、類或變量時(shí)在前面加上__declspec(dllexport)編譯器在編譯DLL項(xiàng)目時(shí)就會(huì)自動(dòng)把這個(gè)符號(hào)標(biāo)記為“需要導(dǎo)出”。鏈接器在生成最終DLL時(shí)會(huì)收集所有被這樣標(biāo)記的符號(hào)自動(dòng)創(chuàng)建導(dǎo)出表并同時(shí)生成對(duì)應(yīng)的LIB文件。這里就是第一個(gè)關(guān)鍵坑點(diǎn)為了讓同一套頭文件既能用于編譯DLL需要dllexport又能用于編譯使用該DLL的客戶端程序需要dllimport我們通常會(huì)使用一個(gè)預(yù)處理宏來(lái)切換就像微軟官方示例那樣// MyLibrary.h #ifdef MYLIBRARY_EXPORTS #define MYLIBRARY_API __declspec(dllexport) #else #define MYLIBRARY_API __declspec(dllimport) #endif // 聲明一個(gè)導(dǎo)出函數(shù) MYLIBRARY_API int add(int a, int b);然后在DLL項(xiàng)目的預(yù)處理器定義中添加MYLIBRARY_EXPORTS。這樣編譯DLL時(shí)MYLIBRARY_API展開為__declspec(dllexport)函數(shù)被標(biāo)記為導(dǎo)出??蛻舳顺绦虬@個(gè)頭文件時(shí)由于沒有定義MYLIBRARY_EXPORTSMYLIBRARY_API展開為__declspec(dllimport)告訴編譯器這個(gè)函數(shù)來(lái)自外部DLL。如果這個(gè)宏定義錯(cuò)了或者根本就沒在DLL項(xiàng)目中定義MYLIBRARY_EXPORTS那么編譯DLL時(shí)函數(shù)就沒有被標(biāo)記為導(dǎo)出鏈接器自然就不會(huì)為它們生成LIB文件中的條目。3. 實(shí)操排查解決未生成LIB文件的完整工作流理解了原理我們就可以按圖索驥一步步排查和解決問(wèn)題。請(qǐng)按照以下流程操作99%的問(wèn)題都能在此解決。3.1 第一步檢查項(xiàng)目類型與基礎(chǔ)配置這是最基礎(chǔ)但也最容易被忽略的一步。如果你創(chuàng)建項(xiàng)目時(shí)選錯(cuò)了類型后續(xù)怎么調(diào)代碼都可能是徒勞。確認(rèn)項(xiàng)目類型在解決方案資源管理器中右鍵點(diǎn)擊你的DLL項(xiàng)目 - “屬性”。在頂部的“配置”中確保選擇的是“所有配置”。然后查看“常規(guī)” - “配置類型”。這里必須顯示為“動(dòng)態(tài)庫(kù)(.dll)”。如果顯示的是“應(yīng)用程序(.exe)”或“靜態(tài)庫(kù)(.lib)”那肯定生成不了DLL的導(dǎo)入庫(kù)。你需要回到項(xiàng)目創(chuàng)建步驟確保選擇了“動(dòng)態(tài)鏈接庫(kù)(DLL)”模板。檢查輸出文件名在屬性頁(yè)中進(jìn)入“鏈接器” - “常規(guī)” - “輸出文件”。默認(rèn)值通常是$(OutDir)$(TargetName)$(TargetExt)例如Debug\MyLibrary.dll。確保擴(kuò)展名是.dll。同時(shí)留意正上方的“導(dǎo)入庫(kù)”設(shè)置通常在“高級(jí)”選項(xiàng)卡里其默認(rèn)值類似$(OutDir)$(TargetName).lib這就是將要生成的LIB文件路徑。如果這個(gè)字段被意外清空或修改LIB就不會(huì)生成。3.2 第二步驗(yàn)證代碼中的導(dǎo)出聲明這是問(wèn)題的核心區(qū)。請(qǐng)打開你的DLL項(xiàng)目的主頭文件通常是聲明公共接口的那個(gè).h文件。情景A使用__declspec(dllexport)宏檢查你的導(dǎo)出宏定義是否正確并且確保在DLL項(xiàng)目的預(yù)處理器中正確定義了觸發(fā)宏。操作如下打開DLL項(xiàng)目屬性頁(yè)。進(jìn)入“C/C” - “預(yù)處理器” - “預(yù)處理器定義”。查看列表中是否包含你的導(dǎo)出宏定義例如MYLIBRARY_EXPORTS。對(duì)于VS2022新建的DLL項(xiàng)目模板通常會(huì)為你自動(dòng)定義一個(gè)名為PROJECTNAME_EXPORTS的宏例如項(xiàng)目名為MathLib則宏為MATHLIB_EXPORTS。你必須使用這個(gè)自動(dòng)定義的宏名或者在你自己的頭文件中與之保持一致。如果不確定一個(gè)簡(jiǎn)單的測(cè)試方法是在你的.cpp文件里添加幾行測(cè)試代碼然后編譯#ifdef MYLIBRARY_EXPORTS #pragma message (MYLIBRARY_EXPORTS is defined! This is being compiled as a DLL.) #else #pragma message (MYLIBRARY_EXPORTS is NOT defined.) #endif編譯時(shí)在輸出窗口看到第一條信息才能證明導(dǎo)出宏生效了。情景B使用.def文件在解決方案資源管理器中檢查你的項(xiàng)目里是否有一個(gè)后綴為.def的文件如MyLibrary.def。如果沒有你可以手動(dòng)添加一個(gè)右鍵項(xiàng)目 - “添加” - “新建項(xiàng)” - “Visual C” - “代碼” - “模塊定義文件(.def)”。打開.def文件其基本結(jié)構(gòu)應(yīng)類似LIBRARY MyLibrary // DLL的名稱 EXPORTS add 1 // 導(dǎo)出的函數(shù)名及可選序號(hào) subtract 2 MyFunction // 也可以不指定序號(hào)關(guān)鍵配置添加了.def文件后必須告訴鏈接器使用它。在項(xiàng)目屬性頁(yè)中進(jìn)入“鏈接器” - “輸入” - “模塊定義文件”確保這里填寫了你的.def文件名如MyLibrary.def。重要注意事項(xiàng)如果同時(shí)使用了.def文件和__declspec(dllexport)鏈接器會(huì)以.def文件為準(zhǔn)。.def文件中未列出的函數(shù)即使標(biāo)記了dllexport也不會(huì)被導(dǎo)出。通常二者選其一即可混用容易造成混亂。3.3 第三步檢查鏈接器高級(jí)設(shè)置有些鏈接器選項(xiàng)會(huì)直接影響LIB的生成?!盁o(wú)入口點(diǎn)”配置錯(cuò)誤在項(xiàng)目屬性中進(jìn)入“鏈接器” - “高級(jí)”。查看“無(wú)入口點(diǎn)”這個(gè)選項(xiàng)。對(duì)于標(biāo)準(zhǔn)的DLL這個(gè)選項(xiàng)應(yīng)該設(shè)置為“否”(/NOENTRY不啟用)。如果被誤設(shè)為“是”鏈接器會(huì)認(rèn)為你在創(chuàng)建一個(gè)沒有DllMain的純資源DLL或其他特殊DLL可能不會(huì)生成標(biāo)準(zhǔn)的導(dǎo)入庫(kù)。“導(dǎo)出所有符號(hào)”慎用在“鏈接器” - “命令行”選項(xiàng)中你可能看到或手動(dòng)添加過(guò)/EXPORT:ALL之類的參數(shù)。這個(gè)參數(shù)會(huì)嘗試導(dǎo)出所有全局函數(shù)和變量但行為不可預(yù)測(cè)且可能導(dǎo)出大量?jī)?nèi)部符號(hào)不建議在正式項(xiàng)目中使用。如果使用了此參數(shù)但仍有問(wèn)題請(qǐng)移除它回歸到使用明確的導(dǎo)出聲明或.def文件。3.4 第四步構(gòu)建并檢查輸出完成上述檢查后清理解決方案“生成” - “清理解決方案”然后重新生成。觀察輸出窗口生成過(guò)程中密切關(guān)注VS2022的“輸出”窗口視圖 - 輸出選擇顯示內(nèi)容為“生成”。在鏈接階段你應(yīng)該能看到類似以下的關(guān)鍵信息1 正在創(chuàng)建庫(kù) D:\Projects\MyLibrary\Debug\MyLibrary.lib 和對(duì)象 D:\Projects\MyLibrary\Debug\MyLibrary.exp這行“正在創(chuàng)建庫(kù)...lib”明確表示鏈接器正在生成LIB文件。如果這行沒有出現(xiàn)說(shuō)明根本沒有導(dǎo)出符號(hào)需要返回第二步仔細(xì)檢查。定位生成文件即使輸出窗口有提示也請(qǐng)親自去輸出目錄通常是項(xiàng)目下的Debug或Release文件夾查看。你應(yīng)該同時(shí)找到MyLibrary.dll和MyLibrary.lib兩個(gè)文件。.exp文件是鏈接過(guò)程中的臨時(shí)文件可以忽略。使用工具驗(yàn)證導(dǎo)出表如果生成了LIB和DLL但客戶端鏈接時(shí)仍報(bào)錯(cuò)可以使用Visual Studio自帶的dumpbin工具驗(yàn)證DLL到底導(dǎo)出了什么。打開“開發(fā)者命令提示符 for VS 2022”切換到你的DLL輸出目錄運(yùn)行dumpbin /exports MyLibrary.dll查看輸出列表中是否有你期望導(dǎo)出的函數(shù)名。函數(shù)名可能會(huì)被C編譯器“修飾”Name Mangling如果看到一堆像?addYAHHHZ這樣的奇怪名字這是正常的C修飾名。如果你想導(dǎo)出C風(fēng)格的、不被修飾的函數(shù)名需要在聲明時(shí)使用extern C就像本文開頭微軟示例中那樣extern C MYLIBRARY_API int add(int a, int b);4. 進(jìn)階場(chǎng)景與疑難雜癥排查即使按照上述流程操作在某些特定場(chǎng)景下可能還會(huì)遇到問(wèn)題。這里分享幾個(gè)我實(shí)踐中遇到的“坑”及其解決方案。4.1 場(chǎng)景從靜態(tài)庫(kù)項(xiàng)目改造而來(lái)有時(shí)候我們可能是在一個(gè)已有的靜態(tài)庫(kù).lib項(xiàng)目上修改配置試圖將其改為動(dòng)態(tài)庫(kù)。這時(shí)除了修改“配置類型”為DLL還有幾個(gè)致命點(diǎn)容易遺漏預(yù)處理器定義靜態(tài)庫(kù)項(xiàng)目通常沒有PROJECTNAME_EXPORTS這個(gè)定義。你必須手動(dòng)在項(xiàng)目屬性的“預(yù)處理器定義”中添加它。函數(shù)聲明靜態(tài)庫(kù)項(xiàng)目的頭文件里一般沒有__declspec(dllexport/dllimport)的宏切換。你必須為所有需要公開的API添加導(dǎo)出/導(dǎo)入聲明。調(diào)用約定不一致檢查函數(shù)聲明是否有明確的調(diào)用約定如__stdcall,__cdecl等。DLL和客戶端必須使用相同的調(diào)用約定。通常使用默認(rèn)的__cdecl或Windows API常用的__stdcall。在導(dǎo)出時(shí)__stdcall函數(shù)在導(dǎo)出表中的名字會(huì)被修飾例如_FunctionName4這需要在.def文件中特別注意或者使用extern C配合__stdcall并指定導(dǎo)出序號(hào)。4.2 場(chǎng)景使用第三方構(gòu)建系統(tǒng)如CMake如果你使用CMake來(lái)生成VS2022項(xiàng)目控制DLL導(dǎo)出的方式有所不同。在CMakeLists.txt中使用add_library命令并指定SHARED來(lái)創(chuàng)建DLL目標(biāo)。導(dǎo)出符號(hào)需要在源代碼中同樣使用__declspec(dllexport)但為了跨平臺(tái)通常會(huì)配合預(yù)定義宏。CMake提供了一個(gè)優(yōu)雅的方案使用GenerateExportHeader模塊。# 在CMakeLists.txt中 include(GenerateExportHeader) add_library(MyLibrary SHARED mylib.cpp) generate_export_header(MyLibrary BASE_NAME MyLibrary EXPORT_MACRO_NAME MYLIBRARY_API EXPORT_FILE_NAME MyLibrary_Export.h) target_include_directories(MyLibrary PRIVATE ${CMAKE_CURRENT_BINARY_DIR})這樣CMake會(huì)自動(dòng)生成一個(gè)MyLibrary_Export.h文件里面定義了MYLIBRARY_API宏。在你的項(xiàng)目頭文件中包含它即可#include MyLibrary_Export.h class MYLIBRARY_API MyClass { ... }; // 類會(huì)被導(dǎo)出 MYLIBRARY_API void myFunction(); // 函數(shù)會(huì)被導(dǎo)出這種方式能自動(dòng)處理Windows下的dllexport/dllimport和其他平臺(tái)如Linux的可見性屬性__attribute__((visibility(default)))。4.3 常見鏈接錯(cuò)誤與含義即使生成了LIB客戶端鏈接時(shí)也可能失敗。以下是幾個(gè)常見錯(cuò)誤LNK2001: 無(wú)法解析的外部符號(hào)?functionNameYAXHZ這明確指向一個(gè)具體的函數(shù)。意味著要么客戶端代碼調(diào)用了這個(gè)函數(shù)但DLL的LIB中沒有導(dǎo)出它檢查DLL的導(dǎo)出聲明要么客戶端項(xiàng)目沒有鏈接到這個(gè)LIB文件檢查客戶端的“附加依賴項(xiàng)”設(shè)置。LNK2019: 無(wú)法解析的外部符號(hào)_functionName4這是一個(gè)使用__stdcall調(diào)用約定的C函數(shù)。同樣檢查DLL是否導(dǎo)出以及客戶端鏈接設(shè)置。錯(cuò)誤 MSB8017: 一個(gè)或多個(gè)文件缺失這通常發(fā)生在生成事件中。如果你設(shè)置了在生成后復(fù)制DLL但指定的源路徑錯(cuò)誤導(dǎo)致復(fù)制失敗可能會(huì)引發(fā)此錯(cuò)誤。檢查項(xiàng)目屬性中“生成事件” - “后期生成事件”里的命令行。4.4 手動(dòng)生成LIB文件最后的手段在極少數(shù)情況下DLL已經(jīng)生成且確認(rèn)有導(dǎo)出函數(shù)但LIB文件丟失或損壞。我們可以使用Visual Studio自帶的lib.exe工具從DLL文件手動(dòng)生成LIB。首先用dumpbin /exports YourDll.dll exports.txt命令將導(dǎo)出列表導(dǎo)出到文本文件。編輯這個(gè)文本文件提取出所有函數(shù)名或修飾名創(chuàng)建一個(gè).def文件。使用lib命令生成LIBlib /def:YourDll.def /machine:x64 /out:YourDll.lib其中/machine:指定平臺(tái)x86, x64等。將生成的YourDll.lib提供給客戶端項(xiàng)目使用。注意這是一個(gè)補(bǔ)救措施并非標(biāo)準(zhǔn)流程。它生成的LIB只包含導(dǎo)出信息不包含調(diào)試信息。最佳實(shí)踐始終是確保DLL項(xiàng)目本身能正確生成LIB。5. 客戶端項(xiàng)目配置要點(diǎn)解決了DLL端的LIB生成問(wèn)題后為了讓客戶端程序能順利使用還需要正確配置客戶端項(xiàng)目。這里有幾個(gè)關(guān)鍵點(diǎn)包含頭文件路徑在客戶端項(xiàng)目屬性中“C/C” - “常規(guī)” - “附加包含目錄”添加DLL公共頭文件.h所在的目錄。鏈接LIB文件在客戶端項(xiàng)目屬性中“鏈接器” - “輸入” - “附加依賴項(xiàng)”添加你的MyLibrary.lib文件名。或者在“鏈接器” - “常規(guī)” - “附加庫(kù)目錄”中添加LIB文件所在路徑然后在“附加依賴項(xiàng)”中寫MyLibrary.lib。運(yùn)行時(shí)DLL位置編譯鏈接通過(guò)后運(yùn)行程序需要能找到DLL。有幾種方法將DLL復(fù)制到客戶端可執(zhí)行文件.exe所在的目錄。將DLL所在目錄添加到系統(tǒng)的PATH環(huán)境變量中。在VS的調(diào)試配置中設(shè)置“調(diào)試” - “環(huán)境”選項(xiàng)例如添加PATHD:\Path\To\Your\Dll;%PATH%。6. 個(gè)人經(jīng)驗(yàn)與避坑總結(jié)回顧這些年處理DLL開發(fā)的問(wèn)題我總結(jié)出幾條血淚教訓(xùn)保持頭文件單一可信源導(dǎo)出/導(dǎo)入的宏定義務(wù)必放在公共頭文件中并且DLL項(xiàng)目和客戶端項(xiàng)目都包含同一個(gè)頭文件。絕對(duì)不要在兩個(gè)地方分別維護(hù)內(nèi)容相似但宏定義不同的頭文件這是滋生不一致性的溫床。新建項(xiàng)目?jī)?yōu)于改造如果目標(biāo)是創(chuàng)建一個(gè)全新的DLL強(qiáng)烈建議直接使用Visual Studio 2022的“動(dòng)態(tài)鏈接庫(kù)(DLL)”項(xiàng)目模板。它會(huì)幫你設(shè)置好大部分基礎(chǔ)配置包括預(yù)處理器定義PROJECTNAME_EXPORTS。這比從一個(gè)控制臺(tái)應(yīng)用或靜態(tài)庫(kù)項(xiàng)目改造過(guò)來(lái)要省心、安全得多?!癉ebug”和“Release”配置要同步檢查很多問(wèn)題在Debug模式下隱藏在Release模式下暴露或者相反。務(wù)必在項(xiàng)目屬性的“配置”下拉框中選中“所有配置”再進(jìn)行設(shè)置或者分別檢查Debug和Release的配置是否一致。特別是預(yù)處理器定義和鏈接器設(shè)置。注意平臺(tái)x86/x64匹配你的DLL是32位x86還是64位x64的客戶端程序必須使用相同位數(shù)的版本。用x86配置編譯的DLL其LIB文件只能用于鏈接x86的客戶端程序。在解決方案平臺(tái)管理器中仔細(xì)核對(duì)。善用#pragma comment(lib, ...)除了在項(xiàng)目屬性中設(shè)置附加依賴項(xiàng)你還可以在客戶端的公共頭文件或源文件中加入一行代碼來(lái)指定鏈接庫(kù)#pragma comment(lib, MyLibrary.lib)這樣只要編譯器能找到MyLibrary.lib通過(guò)附加庫(kù)目錄鏈接就會(huì)自動(dòng)進(jìn)行。這種方法將鏈接依賴關(guān)系直接寫在代碼里對(duì)于小型項(xiàng)目或庫(kù)的分發(fā)可能更清晰。但對(duì)于大型項(xiàng)目集中管理項(xiàng)目屬性仍是更推薦的做法。最后當(dāng)你成功看到Creating library ...這行輸出并且客戶端程序能順利鏈接和運(yùn)行時(shí)那種成就感是實(shí)實(shí)在在的。動(dòng)態(tài)鏈接庫(kù)的開發(fā)確實(shí)比靜態(tài)庫(kù)多了幾分繁瑣但它的優(yōu)勢(shì)——模塊化、節(jié)省內(nèi)存、便于更新——在大型項(xiàng)目和復(fù)雜系統(tǒng)中是不可替代的。希望這份詳細(xì)的指南能幫你掃清Visual Studio 2022下DLL開發(fā)的第一個(gè)也是最重要的一個(gè)障礙。