出閉環(huán))
簡介面向.NET開發(fā)者的Reflector 7.4.1.179綠色注冊版工具包定位于程序集反編譯、源碼導(dǎo)出與閉源組件研究適合需要分析DLL實現(xiàn)、學習控件設(shè)計或排查依賴問題的中高級開發(fā)者。壓縮包共21個文件約4.79MB包含主程序與命令行工具等3個exe、6個dll、4個txt及rtf說明文檔、config配置文件等核心是真正集成的FileDisassembler與FileGenerator兩大常用插件可輔助批量導(dǎo)出源文件、查看程序集結(jié)構(gòu)。已有395人學習下載。其價值在于免安裝注冊即可使用省去單獨尋找和配置插件的麻煩對閉源DLL的源碼還原、控件改造參考、代碼審查與教學演示較有幫助也能為.NET逆向分析提供一套可直接解壓使用的工具組合。對于需要研究非開源組件實現(xiàn)方式的開發(fā)者導(dǎo)出后的源碼雖缺少注釋且變量名有所變化但整體結(jié)構(gòu)仍具參考意義便于在理解邏輯后補充說明并做少量改造復(fù)用。1. 先別急著雙擊Reflector 7.4.1.179 綠色版最容易在插件這一步出錯Reflector 7.4.1.179 綠色注冊版真正值錢的地方不是反編譯本身而是包里已經(jīng)把 FileDisassembler 和 FileGenerator 這兩個插件一起塞進來了前者能把整個程序集一次性導(dǎo)出成按命名空間分目錄的源碼樹后者能把散落的 .cs 文件組裝成能直接打開的工程。聽起來解壓就能用可我見過太多人卡在同一處——主程序能啟動Add-Ins 列表里空空如也或者勾上了插件、菜單就是不出現(xiàn)。綠色版省掉的是安裝向?qū)Р皇沁\行庫和目錄約定.NET Framework 版本、插件 DLL 的位數(shù)、AddIns 目錄的掃描規(guī)則任何一項對不上這套東西就退化成只能看、不能導(dǎo)出的單機反編譯器。下面按我實際部署的順序走先列環(huán)境再掛插件再配導(dǎo)出參數(shù)最后用自己編譯的 Demo 把整條鏈路驗一遍。2. 裝前環(huán)境對照.NET Framework 版本、目錄和權(quán)限三件事綠色版最容易讓人產(chǎn)生“不用裝”的錯覺實際上它只是不寫注冊表、不走安裝向?qū)н\行時依賴一個都不少。Reflector 7.4.1.179 這個年代的版本主程序是托管程序啟動第一件事就是找對應(yīng)版本的 .NET Framework找不到就直接彈一個“需要安裝 .NET Framework”的對話框然后退出連主界面都看不到。插件更挑剔它們是以反射方式被主程序加載的主程序能跑不代表插件能跑。所以裝之前我一般把三件事先定死運行庫版本、解壓目錄、當前用戶權(quán)限。2.1 運行庫版本對照3.5 和 4.x 要分開看這個版本的主程序?qū)?.NET Framework 的依賴常見做法是 3.5 SP1 起步、4.x 兼容運行更穩(wěn)。注意 3.5 和 4.x 在注冊表里是兩條完全獨立的路徑不能只看一個v4\Full就認為 3.5 也裝了。很多人機器上只有 4.x雙擊后報“應(yīng)用程序正常初始化失敗”根子就在這。檢查項注冊表位置判定標準缺失后的表現(xiàn).NET Framework 3.5HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5Install 1主程序閃退或提示初始化失敗.NET Framework 4.xHKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full存在Release值且大于等于 378389主程序能起、插件加載報錯系統(tǒng)位數(shù)$env:PROCESSOR_ARCHITECTUREx86 或 AMD64決定插件 DLL 該用哪個版本用一段 PowerShell 把這兩條路徑一次看完比在“啟用或關(guān)閉 Windows 功能”里翻半天快# 同時檢查 3.5 與 4.x兩條注冊表路徑互不覆蓋缺一條就說明對應(yīng)運行庫沒裝 $keys ( HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5, HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full ) foreach ($k in $keys) { if (Test-Path $k) { $p Get-ItemProperty $k {0} Install{1}, Version{2}, Release{3} -f $k, $p.Install, $p.Version, $p.Release } else { 缺失: $k } }邏輯說明v3.5這條路徑主要看Install是否為 1v4\Full這條路徑看Release378389 對應(yīng) 4.5數(shù)值越大版本越新只要不小于這個數(shù)就能滿足絕大多數(shù) 4.x 兼容場景。參數(shù)說明Get-ItemProperty讀的是默認值之外的命名值所以Install、Version、Release都要顯式取如果某條路徑不存在Test-Path直接返回假腳本不會中斷方便一次看全。補充一句32 位系統(tǒng)上 4.x 的路徑可能是NDP\v4\Client遇到Full不存在時補查Client。2.2 解壓目錄怎么定別放 Program Files綠色版最常見的錯誤放置位置就是C:\Program Files或C:\Program Files (x86)。這兩個目錄受 UAC 保護主程序往自己目錄寫配置、插件往 AddIns 目錄寫緩存時會被系統(tǒng)重定向到VirtualStore表現(xiàn)出來就是“配置改了重啟又變回去”“插件明明放進去了卻加載不到”。我一般的做法是單獨開一個工具盤目錄路徑全英文、不帶空格# 統(tǒng)一放到 D:\Tools 下路徑不帶中文和空格避免插件解析路徑時出問題 $src D:\Downloads\Reflector741.zip $root D:\Tools\Reflector741 New-Item -ItemType Directory -Path $root -Force | Out-Null Expand-Archive -Path $src -DestinationPath $root -Force Get-ChildItem $root | Select-Object Name, Length, LastWriteTime邏輯說明先建目標目錄再解壓-Force保證目錄已存在時不報錯解壓后立刻列一遍文件用來確認壓縮包沒有在傳輸過程中損壞。參數(shù)說明-DestinationPath指向的目錄必須是當前用戶有完全控制權(quán)的普通目錄Expand-Archive在 Windows PowerShell 5.1 上對大文件解壓較慢包體大時可以換 7-Zip但目標路徑的命名規(guī)則不變。目錄定下來之后按下面的清單核一遍文件是否齊全缺哪個后面就會在哪一步出問題文件或目錄作用缺失后的表現(xiàn)Reflector.exe主程序無法啟動Reflector.exe.config運行庫綁定與啟動配置啟動報配置節(jié)錯誤AddIns\插件掃描目錄Add-Ins 列表為空插件 DLL 及依賴FileDisassembler、FileGenerator菜單項不出現(xiàn)版本與注冊說明注冊信息與版本對應(yīng)關(guān)系換機器后提示未注冊2.3 裝前體檢三個動作確認“裸程序”能跑插件出問題的時候最怕分不清是主程序壞了還是插件壞了。所以我習慣在掛插件之前先讓裸程序跑通一次把變量隔離出來。三個動作確認能啟動、確認能打開一個程序集、確認原生導(dǎo)出可用。第一個動作是直接啟動。雙擊沒反應(yīng)時不要反復(fù)點打開事件查看器看 Windows 日志里的“.NET Runtime”條目錯誤信息通常會寫明是哪個程序集加載失敗。第二個動作是找一個手邊的小程序集打開。沒有現(xiàn)成的就自己編一個后面驗證環(huán)節(jié)還要用它一舉兩得// 模擬項目X里的一個服務(wù)類只為了產(chǎn)出一個可反編譯的測試 DLL namespace DemoService { public class PingService { private readonly string _prefix; public PingService(string prefix) { _prefix prefix; } public string Ping(string name) { return _prefix : name; } } }邏輯說明這個類故意包含字段、構(gòu)造函數(shù)和普通方法反編譯后能同時看到字段聲明、構(gòu)造函數(shù)體和字符串拼接方便判斷導(dǎo)出是否完整。參數(shù)說明編譯時用csc /target:library產(chǎn)出 DLL不要用dotnet build因為新 SDK 默認產(chǎn)出的是 .NET Core 程序集老版本 Reflector 打開會提示不支持的格式。第三個動作是右鍵任意類型試一次原生的“導(dǎo)出源碼”。這一步能過說明主程序和運行庫這條鏈路沒問題后面插件再不出現(xiàn)就只可能是插件本身的事。提示整個體檢過程都在沒有掛任何插件的干凈目錄里做。等確認裸程序正常再把插件目錄拷進來出問題才能一眼定位。3. 插件掛載把 FileDisassembler 與 FileGenerator 裝進 Reflector 7.4.1.179主程序跑通之后才輪到插件。這一步是整個部署里最容易反復(fù)的地方因為插件的加載方式在不同小版本、不同漢化包里菜單名會有差異但底層規(guī)則只有兩條插件 DLL 必須能被主程序找到且它的依賴必須和它待在同一目錄。搞清楚這兩條剩下的都是操作順序問題。3.1 先把兩個插件的分工理清楚FileDisassembler 解決的是“批量”問題。Reflector 原生只能選中一個類型導(dǎo)出源碼一個幾百個類型的程序集靠手點基本不現(xiàn)實FileDisassembler 在程序集節(jié)點上加了導(dǎo)出入口可以按命名空間建目錄把整個模塊的源碼一次性寫到磁盤還能選擇導(dǎo)出語言和是否帶上資源文件。FileGenerator 解決的是“組裝”問題。FileDisassembler 導(dǎo)出來的是散落的 .cs 文件沒有工程文件雙擊打不開、編譯不了FileGenerator 讀取導(dǎo)出目錄生成對應(yīng)的.csproj或.vbproj把Compile Include項一條條寫好省掉手工“添加現(xiàn)有項”的體力活。兩者的使用順序是固定的先用 FileDisassembler 導(dǎo)出源碼再用 FileGenerator 在導(dǎo)出目錄上生成工程。順序反了FileGenerator 找不到輸入文件會生成一個空工程或者直接報錯這也是新手最常踩的坑之一。3.2 插件 DLL 的放置與 Add-Ins 加載我優(yōu)先用目錄方式掛載而不是在對話框里逐個添加原因是目錄方式能把依賴一起帶過去不會出現(xiàn)“主 DLL 加載成功、依賴 DLL 找不到”的半成功狀態(tài)。操作順序是先完全退出 Reflector再拷文件再啟動。# 目錄方式掛載整目錄復(fù)制避免只拷主 DLL 漏掉同目錄的依賴 $root D:\Tools\Reflector741 $addins Join-Path $root AddIns New-Item -ItemType Directory -Path $addins -Force | Out-Null Copy-Item .\plugins\* -Destination $addins -Recurse -Force Get-ChildItem $addins -Filter *.dll | ForEach-Object { {0}t{1:N1} KB -f $_.Name, ($_.Length / 1KB) }邏輯說明先確保AddIns目錄存在再把插件包里的全部內(nèi)容遞歸復(fù)制進去最后列出所有 DLL 并帶上大小用來確認拷貝沒有中斷。參數(shù)說明-Recurse保證子目錄里的依賴也一起過去-Force允許覆蓋舊版本插件升級插件時不用手工先刪。如果插件包里自帶readme說明放置路徑以說明為準不同打包方式目錄名可能是AddIns也可能是Add-Ins大小寫和連字符在 Windows 上不敏感但目錄名本身要對。拷完之后啟動主程序打開 Add-Ins 對話框正常情況下能在列表里看到兩個插件條目勾選、關(guān)閉對話框、重啟主程序菜單欄或右鍵菜單里就會出現(xiàn)對應(yīng)入口。這里有個細節(jié)勾選后不重啟菜單是不會刷新的很多人以為沒生效其實是沒重啟。如果不想動程序目錄也可以在 Add-Ins 對話框里手動添加 DLL 路徑。這種方式適合臨時試用缺點是換機器或者移動目錄后路徑失效需要重新添加一遍。我一般只在排查問題時用這種方式做對照實驗。3.3 加載失敗的判定與回退插件加載失敗不會彈很明確的錯誤框多數(shù)時候只是“菜單沒出現(xiàn)”。想確認到底加載沒加載可以看主程序的 Add-Ins 列表列表里有條目但勾選無效說明 DLL 被識別了但初始化失敗列表里壓根沒有條目說明 DLL 沒被掃描到或者位數(shù)不對。判斷位數(shù)可以用一行命令看 DLL 的機器類型PE 頭里Machine字段是0x014c就是 32 位0x8664就是 64 位# 讀 PE 頭判斷插件位數(shù)0x014cx860x8664x640x0200AnyCPU 之外的情況要留意 $dll D:\Tools\Reflector741\AddIns\FileDisassembler.dll $fs [System.IO.File]::OpenRead($dll) $br New-Object System.IO.BinaryReader($fs) $fs.Seek(0x3C, Begin) | Out-Null $pe $br.ReadInt32() $fs.Seek($pe 4, Begin) | Out-Null $machine $br.ReadUInt16() $br.Close(); $fs.Close() Machine 0x{0:X4} -f $machine邏輯說明先定位到 DOS 頭的e_lfanew偏移0x3C讀出 PE 頭位置再跳過簽名讀Machine字段。參數(shù)說明0x014c對應(yīng) x860x8664對應(yīng) x64如果主程序是 32 位而插件是 64 位加載時必然拋BadImageFormatException在事件查看器里能看到完整堆棧。回退策略我固定用二分法先把AddIns目錄清空確認裸程序正常然后只放 FileDisassembler重啟驗證通過后再放 FileGenerator。這樣任何一次失敗都能立刻定位到是哪個插件引入的不用在兩個插件之間來回猜。4. 導(dǎo)出參數(shù)配置FileDisassembler 批量反編譯與 FileGenerator 生成工程插件掛上只是“能用”離“好用”還差一輪參數(shù)配置。這一步?jīng)Q定導(dǎo)出的源碼目錄亂不亂、生成出來的工程能不能直接編譯。我的習慣是先定目錄規(guī)范再定導(dǎo)出參數(shù)最后用腳本把“導(dǎo)出—生成—編譯”串起來保證每次重跑結(jié)果一致。4.1 FileDisassembler 的輸出語言與目錄結(jié)構(gòu)在程序集節(jié)點上右鍵調(diào)出 FileDisassembler 的導(dǎo)出窗口后幾個參數(shù)值得逐一看參數(shù)建議值說明輸出目錄獨立空目錄不要和原始程序集目錄混放避免覆蓋導(dǎo)出語言C#與后續(xù)工程文件類型保持一致按命名空間分目錄開啟大型程序集不開啟會全平鋪在一個目錄導(dǎo)出資源按需資源文件多時關(guān)閉先只導(dǎo)代碼覆蓋已有文件首次導(dǎo)出開啟增量導(dǎo)出時關(guān)閉防止覆蓋手工修改語言選擇要和 FileGenerator 生成的工程類型一致導(dǎo)出 C# 卻生成.vbproj后面編譯必然一堆語法錯誤。另外導(dǎo)出目錄必須是空的或者專用目錄我見過有人在原始 DLL 旁邊直接導(dǎo)出結(jié)果源碼和二進制混在一起清理時誤刪了原始文件。導(dǎo)出前先把目錄準備好導(dǎo)出后立刻統(tǒng)計文件分布能快速判斷是否導(dǎo)出完整# 導(dǎo)出前后都用這段清空輸出目錄導(dǎo)出后按擴展名統(tǒng)計文件數(shù) $out D:\Work\decomp\DemoService\src Remove-Item $out -Recurse -Force -ErrorAction SilentlyContinue New-Item -ItemType Directory -Path $out -Force | Out-Null Get-ChildItem $out -Recurse -File | Group-Object Extension | Sort-Object Count -Descending | Select-Object Name, Count邏輯說明先徹底清空再重建保證每次導(dǎo)出結(jié)果可對比導(dǎo)出完成后按擴展名分組統(tǒng)計.cs數(shù)量應(yīng)該和程序集里的類型數(shù)量大致對得上如果只有零星幾個文件多半是導(dǎo)出范圍選成了單個類型而不是整個程序集。參數(shù)說明-ErrorAction SilentlyContinue用于目錄本來就不存在的情況避免腳本在清理階段中斷Group-Object會把無擴展名的文件歸到空名稱分組資源文件通常就落在這里。大程序集要注意分批。一次導(dǎo)出上萬個文件磁盤寫入不是問題問題在于導(dǎo)出完成后資源管理器索引會卡很久后續(xù) FileGenerator 讀取目錄也會變慢。常見做法是按命名空間分批導(dǎo)出或者先只導(dǎo)主模塊依賴模塊單獨處理。4.2 FileGenerator 生成的工程文件怎么改FileGenerator 在導(dǎo)出目錄上生成工程文件但它只能根據(jù)目錄里現(xiàn)有的文件生成Compile Include不會替你補目標框架和外部引用。生成出來的.csproj通常要手工改兩處目標框架版本和引用列表。!-- FileGenerator 生成的工程一般要補這兩段目標框架和基礎(chǔ)引用 -- PropertyGroup TargetFrameworkVersionv4.0/TargetFrameworkVersion OutputTypeLibrary/OutputType RootNamespaceDemoService/RootNamespace /PropertyGroup ItemGroup Reference IncludeSystem / Reference IncludeSystem.Core / /ItemGroup邏輯說明TargetFrameworkVersion要和原始程序集的編譯目標一致反編譯一個 .NET 4.0 的程序集卻把工程設(shè)為 2.0一些新語法會直接編譯失敗OutputType按原始程序集類型選類庫選Library可執(zhí)行文件選Exe。參數(shù)說明RootNamespace要和源碼里的命名空間對齊否則生成資源文件時會出現(xiàn)命名空間嵌套錯誤Reference里至少要保留System和System.Core用到 LINQ、泛型集合的代碼沒有System.Core會報類型找不到。還有一點要提前有心理預(yù)期反編譯產(chǎn)物不是原樣源碼。迭代器方法會被展開成狀態(tài)機lambda 會變成編譯器生成的類async方法會拆成MoveNext和一堆字段。這些代碼能編譯通過但不代表邏輯結(jié)構(gòu)和原作者寫的一致。所以生成工程后先編譯編譯通過再對照 IL 或行為做驗證不要拿反編譯結(jié)果直接改完就上線。4.3 用批處理把“導(dǎo)出—生成—編譯”串起來目錄我固定分四層raw放原始程序集src放導(dǎo)出源碼proj放生成的工程build放編譯輸出。這樣任何一步出問題都能單獨回滾不會把干凈目錄污染掉。# 目錄約定固定四層編譯輸出單獨放 build出問題只清 build 不動源碼 msbuild D:\Work\decomp\DemoService\proj\DemoService.csproj ^ /t:Rebuild ^ /p:ConfigurationRelease ^ /p:OutputPathD:\Work\decomp\DemoService\build\邏輯說明/t:Rebuild強制全量重編避免增量編譯殘留舊產(chǎn)物掩蓋問題/p:OutputPath必須帶尾部反斜杠否則 MSBuild 會把輸出當成文件名處理。參數(shù)說明ConfigurationRelease用于接近真實發(fā)布環(huán)境的編譯驗證排查問題時可以臨時改成Debug保留符號如果機器上只有新版 MSBuild路徑要換成 Visual Studio 安裝目錄下的MSBuild.exe不要用 .NET SDK 自帶的dotnet build去編老式 csproj。這一步的產(chǎn)物是驗證環(huán)節(jié)的基礎(chǔ)只有build目錄里出現(xiàn)了和原始程序集同名的 DLL才能說明反編譯源碼在語法和引用層面是自洽的。5. 排查清單插件不顯示、導(dǎo)出缺文件、版本對不上前面四章是“照著裝”這一章是“裝壞了怎么救”。下面這幾條都是我在不同機器上真實遇到過的按“現(xiàn)象 → 原因 → 解決”記遇到問題時按順序?qū)φ栈灸芨采w八成情況。5.1 現(xiàn)象主程序雙擊閃退連界面都不出原因最常見的是運行庫缺失或者版本不夠。Reflector 7.x 啟動時會加載對應(yīng)版本的 CLR機器上只有 4.x 而程序配置綁定的是 3.5就會在加載階段直接退出。第二種原因是Reflector.exe.config在解壓過程中損壞配置文件解析失敗同樣不彈窗。解決先按第 2 章的腳本確認 3.5 和 4.x 都裝到位再打開事件查看器看“.NET Runtime”錯誤條目里面會寫明是FileLoadException還是ConfigurationErrorsException。確認是配置問題就重新解壓一份覆蓋config文件不要手工改配置內(nèi)容綠色版的配置文件里可能有打包時寫死的綁定信息。5.2 現(xiàn)象Add-Ins 列表里能看到插件勾選后菜單還是不出現(xiàn)原因插件被識別但初始化失敗多數(shù)是版本不匹配。插件是針對某個主程序版本編譯的接口簽名變了加載時反射調(diào)用失敗主程序會靜默跳過而不是崩潰。另一種情況是勾選后沒有重啟主程序菜單沒刷新。解決先重啟一次確認不是刷新問題仍然不出現(xiàn)就換插件版本插件包里的說明文件通常會寫適配的主程序版本范圍。判斷是否初始化失敗可以在事件查看器里找加載時間點附近的.NET Runtime警告堆棧里會帶插件程序集名。5.3 現(xiàn)象導(dǎo)出到一半報“無法加載程序集”目錄里只有部分文件原因目標程序集引用了同目錄之外的依賴FileDisassembler 在遍歷類型時需要解析這些依賴解析不到就中斷當前分支。大型項目里依賴散落在多個子目錄時特別常見。解決把被依賴的 DLL 復(fù)制到原始程序集同目錄或者在導(dǎo)出窗口里先把范圍限制在主模塊依賴模塊單獨導(dǎo)出。不要指望插件自動去 GAC 里找綠色版沒有裝配探測路徑的配置能力。5.4 現(xiàn)象FileGenerator 生成的工程一打開滿屏紅線原因目標框架版本不對或者缺少基礎(chǔ)引用。反編譯出來的代碼里用了System.Linq、System.Threading.Tasks而工程文件里只有默認的System引用。解決按 4.2 節(jié)補TargetFrameworkVersion和Reference補完先編譯一次看錯誤數(shù)量是否明顯下降。如果還剩大量“找不到類型”檢查是不是導(dǎo)出時漏了某個依賴模塊回到 5.3 處理。5.5 現(xiàn)象換一臺機器后提示未注冊或者插件目錄被清空原因綠色版的注冊信息和使用痕跡通常落在用戶配置目錄不在程序目錄里。只拷程序目錄過去配置沒跟過來就會提示未注冊。另一種情況是殺毒軟件把插件 DLL 當成可疑文件隔離了表現(xiàn)和“插件沒放進去”一模一樣。解決遷移時把程序目錄和用戶配置目錄一起打包不要只拷 exe換機器后先看殺毒軟件的隔離區(qū)確認插件 DLL 是否被移走必要時把工具目錄加入白名單。有條件還是走正版授權(quán)渠道省掉這類遷移問題。6. 裝完怎么驗證用一個 Demo DLL 跑通反編譯閉環(huán)驗證這一步很多人會跳過覺得主程序能打開、菜單能點就算裝好了。我的標準是自己編一個 DLL用這套環(huán)境完整走一遍“打開 → 反編譯 → 導(dǎo)出 → 生成工程 → 編譯通過”五步都過才算真正跑通。原因很簡單拿別人的程序集驗證你分不清失敗是環(huán)境問題還是那個程序集本身的依賴問題拿自己編的 DLL所有變量都可控。驗證用的 Demo 就是第 2 章那段PingService編譯成DemoService.dll之后按下面的表逐項過驗證項動作通過標準主程序加載打開DemoService.dll樹里能看到PingService類型和字段原生反編譯選中類型看反編譯窗格構(gòu)造函數(shù)和方法體完整顯示插件入口程序集節(jié)點右鍵出現(xiàn) FileDisassembler 與 FileGenerator 菜單批量導(dǎo)出用 FileDisassembler 導(dǎo)出到src目錄中出現(xiàn)對應(yīng)命名空間的.cs文件工程生成用 FileGenerator 生成到proj生成.csproj且Compile Include條目齊全編譯驗證執(zhí)行 4.3 節(jié)的 msbuild 命令build目錄出現(xiàn)同名 DLL退出碼為 0導(dǎo)出之后我還會做一個動作打開導(dǎo)出的.cs文件對照原始源碼看方法簽名和字符串常量。反編譯工具偶爾會把屬性寫成字段加get_/set_方法或者把自動屬性展開成帶私有字段的寫法這些都屬于正常變形但如果方法體整個缺失、只剩一個throw new NotImplementedException()那說明導(dǎo)出鏈路有問題要回到 5.3 檢查依賴。# 驗證產(chǎn)物是否齊全源碼文件數(shù)、工程文件、編譯輸出三層各查一次 $base D:\Work\decomp\DemoService 源碼文件: {0} -f (Get-ChildItem $base\src -Recurse -Filter *.cs | Measure-Object).Count 工程文件: {0} -f (Get-ChildItem $base\proj -Filter *.csproj | Measure-Object).Count 編譯產(chǎn)物: {0} -f (Get-ChildItem $base\build -Filter DemoService.dll | Measure-Object).Count邏輯說明三個數(shù)字分別對應(yīng)導(dǎo)出、生成、編譯三個階段任何一個為 0 都說明該階段沒走通不用繼續(xù)往下看。參數(shù)說明統(tǒng)計源碼文件時限定*.cs避免把資源文件算進去干擾判斷編譯產(chǎn)物按文件名精確匹配防止把依賴 DLL 也算進來。這套驗證我每次都走包括只換了一臺機器、只升級了一個插件的情況。有一次就是靠它發(fā)現(xiàn)新拷過去的插件包少了一個依賴 DLL主程序能啟動、菜單也出現(xiàn)了但一點導(dǎo)出就靜默失敗源碼目錄里只有零個文件。從那以后我每次部署完都強制走一遍這個五步閉環(huán)寧可多花十分鐘也不在導(dǎo)出到一半的時候才發(fā)現(xiàn)問題。希望幫到你。本文還有配套的精品資源點擊獲取