Windows 應用程式因程式錯誤的例外掉下也要確實留下日誌 - 不賭 in-process 的設計與 WER / 最終日誌 / 監視程序的最佳實踐
· 小村 豪 · Windows 開發, 例外處理, 日誌, WER, 當機傾印, 缺陷調查
Windows 應用程式的缺陷調查中最痛苦的是 只知道掉了,但為什麼掉沒有留下 的狀態。
特別是以下的案件中這個問題會相當重。
- 只在客戶環境掉
- 只在長時間運轉的最後掉
- WPF / WinForms / Windows 服務 / 常駐應用程式中重現率低
- COM、P/Invoke、native DLL、vendor SDK 相關
- 「例外訊息」能取得,但沒有之前的脈絡
但是最初老實說,只用掉下側的程序不能「一定」留下日誌。 包含堆疊破損、記憶體破壞、fast fail、強制終止、電源斷電,in-process 的最後日誌本質上是 best effort。
實務上該目標的是 不期待掉下程序中 的構成。 也就是,
- 通常時的時序日誌
- 掉下瞬間的最終當機標記
- OS 或別程序側留下的當機證跡
這 3 層思考。
本文以 Windows 桌面應用程式、常駐應用程式、Windows 服務、裝置連動工具為前提,整理 因程式錯誤的例外掉下也不失去調查可能性的最佳實踐。
1. 先講結論
先排結論。
- 不把「最後的日誌」賭在 1 個 in-process 處理器 最重要。
- 實務上最無難的是 通常日誌 + 最終當機標記 + WER LocalDumps 的組合。
- 長時間運轉、裝置連動、外掛、native SDK 混在的話,加上監視程序(watchdog / launcher / service) 會相當強。
- 當機處理器中 不做重處理 是鐵則。壓縮、HTTP 送信、DI 解析、UI 對話方塊、複雜的 JSON 產生要排除。
- 當機時只往本地短短留下,壓縮・上傳・通知放到 下次啟動後或別程序。
- 用 WinForms 的
ThreadException或 WPF 的DispatcherUnhandledException讓外觀延命的設計,對程式錯誤而言危險。 - .NET 和 native 中 懷疑損壞狀態的例外以「記錄後終止」而非「復原」 為基本比較安全。
- 要取得傾印,必須同時保存 PDB 和發佈的二進位 否則之後讀不了。
簡言之最佳實踐是 「不要在掉下的瞬間做全部。把掉下前・掉下瞬間・掉下後分工」 。
2. 為什麼只有 in-process 不能「確實」
這裡曖昧設計會搖擺。
2.1 掉下的執行緒的脈絡本身可能已壞
未處理例外的鉤子或最上層例外過濾器 可能在壞掉那側的執行緒脈絡上運作。 這時,
- 堆疊已經危險
- 堆損壞額外配置危險
- 例外發生時持有的鎖導致等待會停
- logger 本身依賴的物件已壞
這些普通存在。
所以 把最後的處理器看作「什麼都能做的地方」不如看作「能做的事相當少的地方」 比較安全。
2.2 fast fail 或損壞狀態例外以「最小 in-process 動作」為前提
記憶體破壞或致命狀態中不要期待通常例外處理比較好。
特別 native 側的 __fastfail 系或懷疑損壞狀態的異常,以 「以盡可能少的額外開銷立即終止」 方向設計。
也就是說 最後的 in-process 日誌能寫算運氣好,主證跡在 OS / 別程序側 這思考方式自然。
2.3 .NET 的未處理例外事件也不是「重復原處理」的場合
.NET 的 AppDomain.UnhandledException 雖方便,
這裡該做的看作到 短記錄 為止比較好。
- 受例外發生時持有鎖的影響
- 不是損壞狀態例外都能安全取得
- 這裡勉強做持續方針容易以半壞狀態延命
簡言之 「未處理例外事件 = 最後的通知」,「不是安全的復原點」。
3. 推薦架構 - 分開 crash-time 和 after-restart
最容易整理的是分開 當機時做的 和 重新啟動後做的。
| 階段 | 目的 | 在哪運作 | 做的事 |
|---|---|---|---|
| 通常時 | 留下時序 | 應用程式內 | 結構化日誌、heartbeat、邊界事件 |
| 當機時 | 留下最低限證跡 | 應用程式內 + OS | 最終當機標記、WER 傾印 |
| 終止直後 | 偵測 unexpected exit | 別程序 | 記錄 exit code、判斷重新啟動、通知 |
| 下次啟動後 | 做重的後處理 | 新的健全程序 | 壓縮、上傳、使用者通知、整理舊日誌 |
這樣分設計相當穩定。
3.1 最小構成
小型業務工具或公司內部用 WPF / WinForms 的話,先用以下通常就夠。
- 通常日誌: 本地的 append-only 檔
- 最終當機標記: 專用的短檔
- 傾印: WER LocalDumps
- 下次啟動時: 顯示「前次異常終止。有診斷資訊」
3.2 強化構成
以下要件的話加強 1 段比較好。
- 24/7 運轉
- 裝置控制、監視、常駐
- 多 COM / P/Invoke / native SDK
- 有子程序、外掛、腳本執行
- 客戶環境不允許「停著」
這種情況,
- worker 程序: 本體處理
- launcher / watchdog / service: 啟動監視、記錄 exit、重新啟動
- WER LocalDumps: worker 側
- 下次啟動或 watchdog: 回收診斷資訊
這樣分相當實務向。
4. 通常日誌的最佳實踐
試圖只用當機時的最後 1 行戰鬥通常會輸。 真正有效的是 到之前為止的通常日誌。
4.1 日誌比起「人類用文章」,是「之後能相關的資訊」
通常日誌至少放入以下。
- UTC 時間戳記
- 從程序開始經過時間
- PID / TID
- 應用程式名、版本、建置編號、提交識別碼
- 工作階段 ID
- 操作 ID / 工作 ID / 相關 ID
- 模組名 / 畫面名 / worker 名
- 之前的外部作用
- 檔案寫入
- DB 更新
- 裝置命令傳送
- 通訊要求
- 例外類型、HRESULT / Win32 錯誤 / 例外代碼
- 主要輸入參數的摘要
- 不含機密範圍內的對象 ID
推薦 1 行 1 事件的 JSON Lines 或 key=value 格式。
比起留下人類用長文,「之後能對照 3 個檔案」 更重要。
4.2 關鍵事件同步留下
通常日誌全部同步寫會重。 但全部交給非同步緩衝,掉下的瞬間會一起消失。
所以實務上以下分法好處理。
Information的細事件: 可緩衝Warning以上: 早 flush- 重要的邊界事件: 同步留下
- ProcessStart
- ConfigLoaded
- WorkerStarted
- ExternalCommandSent
- TransactionCommitted
- RecoveryStarted
- FatalPathEntered
重點是 業務上的邊界要好好落到地面。
4.3 分開「現在寫的通常日誌」和「最後的當機標記」
這相當重要。
試圖把全部放入 1 個 rolling log,
- 正在 rotation
- 留在非同步佇列
- 例外發生直後 logger 本身死了
- 日誌行中途切斷
會發生這些事。
所以至少分成以下 2 個推薦。
app-<session>.jsonl通常時序日誌fatal-last.log或fatal-<session>.log最終當機標記專用
「最後 1 行留在哪」明確 在現場相當有幫助。
4.4 日誌儲存位置固定本地,不用網路處
當機時依賴 UNC 路徑、NAS、HTTP、雲 API 很危險。
- 網路瞬斷
- DNS 延遲
- 憑證失效
- UI 執行緒的等待
- 服務帳戶權限不足
會相關。
當機時 先往本地固定路徑 落下。 發送放到 下次啟動後或別程序。
4.5 檔名放入 session
光日期不夠。 因為同天會重啟很多次。
推薦例如以下。
Logs\
MyApp_20260318_101530_pid1234_session-4f1c.jsonl
MyApp_fatal_20260318_101533_pid1234_session-4f1c.log
MyApp_watchdog_20260318.jsonl
「是哪個啟動實例的話」 明確就讓解析速度相當不同。
5. 最終當機標記的最佳實踐
這裡不是做 全功能 logger 的地方。 是 只 1 次、短、偏確實地留下 的地方。
5.1 目的不是「原因的詳細」而是「入口的固定」
最終當機標記該放的資訊縮小比較強。
- 發生 UTC
- PID / TID
- 工作階段 ID
- 版本 / 建置編號
- 從哪個鉤子來
AppDomain.UnhandledExceptionApplication.ThreadExceptionDispatcherUnhandledExceptionSetUnhandledExceptionFilter_set_invalid_parameter_handlerset_terminate
- 例外類型或例外代碼
- 可能的話簡單訊息
- 之前的操作 ID
- 通常日誌的檔名
- dump 預期資料夾
這些就夠。
5.2 當機處理器中不該做的
以下相當高機率是地雷。
- 從 DI 容器解析 logger
- 使用 async / await
- 丟 Task
- 鎖等待
- 組複雜的 JSON
- 碰 COM 物件
- 顯示 UI 對話方塊
- 壓縮
- HTTP / SMTP / Slack / Teams 傳送
- 解析 dump 並摘要
- 吞下例外繼續
當機處理器 不是普通處理流程的延續。 往「只做最小本地寫入並結束」偏。
5.3 當機處理器該做的
相反該做的相當單純。
- 防止多重進入
- 只寫 1 行
- flush
- 終止
這個順序。
盡可能,
- 事先建立的專用資料夾
- 事先存在確認的路徑
- ACL 確認過的儲存位置
使用。
通常日誌 flush 太多會重,但 fatal 標記件數極少,所以這裡可以強 flush。
.NET 是 FileStream.Flush(true),native 是 FlushFileBuffers 這類 「這 1 行立刻落到地面」 的處理容易設計。
5.4 不要試圖讓它繼續
程式錯誤起點的 unexpected 例外,最終處理器看作 不是復原裝置而是記錄裝置 比較安全。
特別以下「不繼續」為基本。
- 即使
NullReferenceException或InvalidOperationException,共享狀態更新途中 - UI 執行緒的 unexpected 例外
- 監視迴圈或父迴圈漏的 unexpected 例外
AccessViolationExceptionStackOverflowException- native 邊界的異常
- CRT 的 invalid parameter / purecall / terminate
「不想掉下來」的心情可理解,但 半壞狀態延命比較痛苦,診斷和運營都 很多。
要終止時,.NET 用 Environment.FailFast,native 用 RaiseFailFastException 或 __fastfail 這類 立即終止系 API,不期待 finally 或通常的後續處理的設計比較安全。
6. 各框架的注意點
6.1 .NET 通用: AppDomain.CurrentDomain.UnhandledException
這作為 最後通知 有用。 但這裡避免重的復原處理。
基本用法如下。
- 寫最終當機標記
- 必要時在 Windows Event Log 留最小訊息
- 不繼續
- 這裡不做等待或重試
UnhandledException 雖方便,但 不要以為這裡能把應用程式回到健康狀態 比較安全。
6.2 WinForms: Application.ThreadException
這難在 能接住 UI 執行緒的未處理例外並外觀上繼續。
業務輸入的預期內錯誤做對話方塊化的用途還可以,但 不適合程式錯誤起點的 unexpected 例外繼續的用途。
真的要優先原因調查的話,
ThreadException中只做最小記錄- 或偏向
UnhandledExceptionMode.ThrowException - 在此基礎上終止程序,留下傾印和日誌
比較安全。
6.3 WPF: Application.DispatcherUnhandledException
WPF 也類似。
- 只以 UI 執行緒的例外為主對象
- 設
Handled = true能外觀上繼續 - 但對程式錯誤做這個,畫面狀態和內部狀態容易偏差
所以 WPF 也是 不作為繼續用的延命裝置,作為記錄的入口使用 比較無難。
6.4 TaskScheduler.UnobservedTaskException 不作主路徑
這不是 「掉下前的最後防線」。
偵測 Task 的例外漏的輔助可用,但
作為當機時的確實記錄路徑弱。
所以,
- 早期發現例外觀測漏
- 開發中挖出
Task的設計漏
用途用,但 不作為最終當機處理器的主角 比較好。
6.5 native Win32 / C++: 不過信 SetUnhandledExceptionFilter
native 側容易期待 SetUnhandledExceptionFilter。
但這 在 faulting thread 的脈絡運作,
- 無效堆疊
- 深遞迴
- 已壞的堆
- 例外發生時的鎖持有
會受影響。
因此 SetUnhandledExceptionFilter 看作
接最後通知的 best effort 的入口 剛好。
6.6 native C++ 也抓 CRT 的終止路徑
native C++ 中只看未處理 SEH 會漏。
想看的例如以下。
_set_invalid_parameter_handler_set_purecall_handlerset_terminate
這系列是為了抓 C 執行環境或 C++ 執行環境起點的「終止路徑」。
實務上,
- 這些處理器也寫最終當機標記
- 但不做重的復原處理
- 確實終止
- 主證跡交給 WER / dump
無難。
7. 以 WER LocalDumps 為基礎
這在實務上相當強。
7.1 首推是 WER LocalDumps
在 「掉下後偏確實地留下最低限證跡」 的意義上, 先是 WER LocalDumps 最好處理。
理由單純。
- 能在 OS 側留傾印
- 沒有追加工具容易放入
- 能以應用程式單位設定
- 能把當機時的主證跡逃到 in-process 以外
光靠日誌不知道的
- 哪個執行緒掉
- 在哪個堆疊掉
- 哪個模組邊界
- managed / native / COM / SDK 哪個可疑
之後能看是強的。
7.2 典型設定
例如對 MyApp.exe 在 C:\CrashDumps\MyApp 留傾印的話可以如下。
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpFolder /t REG_EXPAND_SZ /d "C:\CrashDumps\MyApp" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpCount /t REG_DWORD /d 10 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpType /t REG_DWORD /d 2 /f
最初以下思考方式就好。
| 值 | 首推 |
|---|---|
DumpFolder |
專用資料夾 |
DumpCount |
5~10 |
DumpType |
開發機 2,現場看容量和機密要件 1 or 2 |
7.3 一定要確認 dump 儲存位置的 ACL
日誌和傾印都一樣,設定到無法寫的資料夾沒意義。
特別,
- Windows 服務
- 權限分離的子程序
- 現場機的限制帳戶
- 與 UAC 相關
儲存位置 ACL 是落空的主因。
儲存位置,
- 事先建立
- 寫入測試
- 保留數限制
- 運營擔當能去看的位置
確認到這裡。
7.4 想在 WER 報告附加目前日誌時
對 Microsoft 的 WER 報告或自訂 WER 運營,也有用 WerRegisterFile 為了把目前日誌檔加到錯誤報告進行註冊 的方法。
但這裡看作 不是本地儲存的替代而是追加導線 比較安全。 當機時真正想要的先是 手邊終端偏確實地留下。
順序是,
- 本地通常日誌
- 本地 fatal 標記
- 本地 dump
- 必要時也在 WER 傳送路徑註冊相關檔
比較實務向。
7.5 不只傾印也留版本管理
取得傾印後之後,
- 那時的 EXE / DLL 沒了
- 沒 PDB
- 不知道哪個提交的建置
會相當弱。
至少留以下。
- 已發佈的二進位
- 對應的 PDB
- 版本
- 建置日期時間
- 提交識別碼
- 安裝程式版本
傾印收集和 PDB 保存是 套組。
8. 使用 MiniDumpWriteDump 或獨自當機回報器時的思考方式
也有需要獨自實作的場面。
- 想從 UI 顯示「儲存診斷資訊」按鈕
- 想把日誌或設定檔也打包
- 想把子程序群一起處理
- 想在自動上傳前放入獨自遮罩
但這裡最重要的是 不要讓取 dump 的處理也由掉下側背負太多。
8.1 比起 self-dump 用別程序
MiniDumpWriteDump 強大但
比起從當機的那個程序中呼叫,從別程序呼叫更安全。
典型構成如下。
- worker 本體偵測異常
- 可能的話用事件或命名管道通知 helper
- helper 取 worker 的 dump
- helper 打包
tail日誌或設定檔 - helper 終止後放到上傳佇列
這樣 worker 壞了 helper 側還健全。
8.2 真的要 in-process 就偏向專用執行緒
不能別程序化的情況也, 把專用執行緒作為 dump 專用 比較好。
但即使如此本質是 best effort。 「放入獨自 dump 實作所以 100% 安心」不成立。
8.3 重的事放到下次啟動後
獨自回報器容易想做的事。
- zip 壓縮
- 與 symbol 資訊對照
- 伺服器上傳
- 畫面截圖
- 從 DB 取得追加資訊
這些放到 不是當機時而是重啟後或 helper 側。
9. 加入監視程序會改變什麼
長時間運轉系中監視程序相當有效。
9.1 監視程序留的東西
watchdog / launcher / 父服務,例如能留以下。
- 子程序開始時刻
- 啟動引數
- PID
- 監視對象版本
- heartbeat 的最終接收時刻
- 終止時刻
- exit code
- restart 次數
- dump 有無
- 是否重啟
光這些就,
- 真的當機
- OS 關機
- 使用者關
- hang 被 kill
- 重啟迴圈幾次
相當看得到。
9.2 特別適合的情況
以下的話相當積極考慮分離。
- 抱 vendor SDK 的 worker
- 影像處理 / 影片處理 / device I/O
- 監視或輪詢的父迴圈
- 腳本或外掛執行
- COM / ActiveX 既有資產的主機
- 64bit / 32bit 橋接或互通
把危險處理關進 1 個 worker 日誌設計和復原設計都變輕鬆。
10. 常見的 NG
10.1 catch (Exception) 只輸出日誌後繼續
最常見也最危險。
- 途中變更留
- 共享狀態壞
- 後續障礙增
- 真正原因點模糊
日誌增 1 行的代價是 事故拖長 多。
10.2 只信 async logger 的佇列
非同步日誌本身不壞。 問題是 fatal path 也往同一佇列堆積就結束。
掉下瞬間 worker 停,那整個佇列會消失。
只 fatal path 直接寫 留逃避路徑比較安全。
10.3 在當機處理器 HTTP 傳送
想實作,但相當危險。
- DNS
- TLS
- proxy
- 認證
- 逾時
- 重送等待
全部搭在掉下的脈絡。
傳送放到 重啟後。
10.4 有 dump 但和通常日誌不結合
這多。
- 傾印檔名沒 session
- 日誌側沒 PID / session
- watchdog 側沒 PID
- build 編號不一致
結果 3 個證跡看起來像不同的話。
10.5 用 WinForms / WPF 的未處理例外事件延命
外觀「不掉了」最初會被喜歡。 但實際上
- 只剩畫面
- worker 死
- 只剩按鈕啟用
- 不知是否保存
會造成殭屍狀態。
10.6 沒看 native 側的終止路徑
只用 SetUnhandledExceptionFilter 放心會漏,
- invalid parameter
- purecall
- terminate
- fast fail
這側。
native C++ 中 不只 SEH,也意識 CRT / C++ 執行環境側的終止路徑 比較好。
11. 最低限的導入檢核表
滿足以下會相當實戰。
- 通常日誌以 1 行 1 事件留
- 所有日誌有 UTC、PID、TID、version、session
ProcessStart和ProcessExit留- 重要邊界事件同步 flush
- 有最終當機標記專用檔
- fatal path 不經過 async logger
- WER LocalDumps 以應用程式單位設定
- 驗證 dump 儲存位置的 ACL
- 保存 PDB 和發佈的二進位
- 下次啟動時能偵測前次異常終止
- 壓縮 / 上傳 / 通知在重啟後或別程序做
- native C++ 中也整理 invalid parameter / purecall / terminate
- 在驗證機意圖地讓它掉,確認 真的留下
最後 1 行特別重要。 光設計沒意義,一定要做「取得到試驗」。
12. 試驗到哪
推薦的確認項目如下。
| 試驗 | 確認什麼 |
|---|---|
| managed 的未處理例外 | 通常日誌、fatal 標記、dump 是否都齊 |
| UI 執行緒例外 | WinForms / WPF 的事件路徑是否如預期 |
| worker 執行緒例外 | 是否到 AppDomain.UnhandledException,watchdog 能否偵測 |
| native 例外 | WER dump 是否真的取得 |
| invalid parameter / terminate | CRT / C++ 執行環境路徑也是否留最小記錄 |
| 強制 kill | in-process 不可能但 watchdog 側能否記錄 unexpected exit |
| 重啟 | 下次啟動後的通知、回收、上傳是否動作 |
不是「例外飛就該有日誌」,而是「在這條件這個檔案會留」確認 重要。
13. 總結
Windows 應用程式即使因程式錯誤的例外掉也想留調查必要資訊,思考方式的軸相當單純。
- 不期待只靠掉下側的程序
- 分為通常日誌、最終當機標記、OS / 別程序側的證跡
- 當機時只往本地短短留
- 重處理放到重啟後或別程序
- 以 WER LocalDumps 為基礎
- 比起繼續,以記錄後終止為基本
簡言之, 「努力最後 1 行」不如「做就算沒最後 1 行也能追的構成」 更強。
即使如此還想要最後 1 行,所以 最終當機標記在別檔短短留。 然後真正的主證跡給 WER 的 dump 和到之前為止的通常日誌。 這是 Windows 應用程式實務上相當穩定的做法。
相關文章
參考資料
- Microsoft Learn: Collecting User-Mode Dumps https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
- Microsoft Learn: Using WER https://learn.microsoft.com/en-us/windows/win32/wer/using-wer
- Microsoft Learn: MiniDumpWriteDump function https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump
- Microsoft Learn: SetUnhandledExceptionFilter function https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setunhandledexceptionfilter
- Microsoft Learn: System.AppDomain.UnhandledException event https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-appdomain-unhandledexception
- Microsoft Learn: Application.ThreadException Event https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.application.threadexception
- Microsoft Learn: Application.DispatcherUnhandledException Event https://learn.microsoft.com/en-us/dotnet/api/system.windows.application.dispatcherunhandledexception
- Microsoft Learn: TaskScheduler.UnobservedTaskException Event https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler.unobservedtaskexception
- Microsoft Learn: Environment.FailFast https://learn.microsoft.com/en-us/dotnet/api/system.environment.failfast
- Microsoft Learn: Registering for Application Recovery https://learn.microsoft.com/en-us/windows/win32/recovery/registering-for-application-recovery
- Microsoft Learn: RegisterApplicationRecoveryCallback https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrecoverycallback
- Microsoft Learn: WerRegisterFile https://learn.microsoft.com/en-us/windows/win32/api/werapi/nf-werapi-werregisterfile
- Microsoft Learn: _set_invalid_parameter_handler https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/set-invalid-parameter-handler-set-thread-local-invalid-parameter-handler
- Microsoft Learn: _set_purecall_handler https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-purecall-handler-set-purecall-handler
- Microsoft Learn: set_terminate https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/set-terminate-crt
- Microsoft Learn: __fastfail https://learn.microsoft.com/en-us/cpp/intrinsics/fastfail
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
應該在哪裡 `catch` 例外並輸出日誌、進行錯誤處理 - 以實務向整理呼叫階層的邊界與職責
本文整理在呼叫階層中應該於哪一層 catch 例外、輸出主日誌與進行錯誤處理的實務判斷標準。深層 helper 不寬泛接捕,外部 I/O 邊界負責翻譯例外,UseCase 把預期內失敗結果化,UI 與請求邊界輸出 1 次主日誌並決定回應,未處理例外處理器只承擔最終記錄與終止...
Windows 應用的 crash dump 收集入門 - 先搞清楚 WER / ProcDump / WinDbg 怎麼分工
本文整理在 Windows 應用追難以重現的 crash 時,要先以 WER LocalDumps 應用單位設定為起手式,再依現場狀況追加 ProcDump,最後才考慮 MiniDumpWriteDump 自製收集的決策順序。讀完能理解 mini 與 full dump 的...
發生非預期例外時的 checklist - 要讓應用結束還是繼續,先看的判斷表
本文以 C# / .NET 與 Windows 應用為前提,把非預期例外發生後該結束還是繼續的判斷拆成失敗單位、共用狀態、外部副作用、原生邊界四個觀察點,並提供判斷表與典型情境,協助讀者在 catch 之前先判斷是否還能信任應用狀態。
開發 COM 元件、OCX/ActiveX 時常見的坑 - 整理 Visual Studio 的 32bit/64bit、註冊、管理員權限
整理開發 COM、OCX、ActiveX 元件時最容易卡關的四個面向:宿主行程的 32bit/64bit、Visual Studio 2022 變成 64bit 後的設計時整合、regsvr32 與 Regasm 的註冊位置、以及管理員權限與 HKCU/HKLM 的關係,協...
ClickOnce 是什麼 - 以實務視角整理機制、更新、適合場面・不適合場面
本文以實務視角整理 ClickOnce 是什麼,從 manifest、快取、更新、簽章的構造,到適合公司內部 .NET 桌面業務應用程式的案件與不適合 machine-wide 或 service、driver 等深度 OS 整合的案件,幫助讀者判斷是否採用並掌握 depl...
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
Windows 應用程式開發
支援包含常駐處理、設備連動、運作日誌與可維護結構的 Windows 桌面應用程式。
故障調查 & 根本原因分析
調查難以重現的故障、長時間執行後的問題、記憶體洩漏、通訊停滯等棘手的正式環境問題。
作者檔案
本文作者的個人檔案頁面。
Go Komura
小村軟體有限公司 代表
以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。