Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8cd4f3c
dynafix: split tables, hint UI, options, screen and PEGRC into includ…
timliudev Oct 17, 2026
e001058
Share the log lock, clock and update value names of launcher and upda…
timliudev Oct 17, 2026
d3b9deb
Merge update_run and update_offer into update_prompt(policy)
timliudev Oct 17, 2026
b4a59b6
Split the launcher's entry point into parse_args, elevation_gate, sta…
timliudev Oct 17, 2026
314e7d5
Tests: VM regression checklist
timliudev Oct 17, 2026
2db0263
Tests: characterization tests for command line, elevated arguments an…
timliudev Oct 17, 2026
0609115
Move promote_com_in and zip_extract_all out of the shipped code into …
timliudev Oct 17, 2026
2a1faa5
Wizard: the "Close DynaRun and install" consent covers one install jo…
timliudev Oct 17, 2026
e66d23d
Move the remaining test-only COM helpers into the tests
timliudev Oct 17, 2026
cb1aa28
dynafix: PEGRC loader callback takes peg_check's busy flag, defers wh…
timliudev Oct 17, 2026
0c729d6
Name the result codes in errors.h (values unchanged)
timliudev Oct 17, 2026
dee0b65
Shared helpers: path join, run_process, directory walk, app key
timliudev Oct 17, 2026
cccfb3d
install_opts: pass the install options explicitly instead of through …
timliudev Oct 17, 2026
50bd20d
Command line: one verb table for the setup and driver stages
timliudev Oct 17, 2026
4089309
Shortcuts: one list of shortcut folders, walks use dir_walk
timliudev Oct 17, 2026
0791e0e
Shortcuts: skip a shortcut folder whose path is too long instead of o…
timliudev Oct 17, 2026
a2197ff
trust_ctx and msi_api_init: no hidden state for the user SID, exe tru…
timliudev Oct 17, 2026
487e6c7
Split setup.c into topic files included by setup.c (one compilation u…
timliudev Oct 17, 2026
732c20a
Zip: one central directory reader
timliudev Oct 17, 2026
60fb2c7
Driver: pass tool and package-log settings as arguments
timliudev Oct 17, 2026
4f82272
Driver: prep_locked with one exit
timliudev Oct 17, 2026
948ee1f
Driver: remove the staged files and accepted.txt when the preparation…
timliudev Oct 17, 2026
d103f7e
Split setup.h into module headers (setup.h stays as an umbrella)
timliudev Oct 17, 2026
32c4645
Wizard: job table instead of job switches
timliudev Oct 17, 2026
3bbb038
Wizard: one flow value instead of the g_pre/g_driver_only/g_drvmode c…
timliudev Oct 17, 2026
0a83fb0
Wizard: page table, one enter function per page
timliudev Oct 17, 2026
9d899bf
Wizard: explicit result instead of deriving the exit code from the page
timliudev Oct 17, 2026
a6f5243
Split wizard.c into flow files included by wizard.c (one compilation …
timliudev Oct 17, 2026
7410430
Wizard: wizard_state, worker input and output handed over in structs
timliudev Oct 17, 2026
1c8498e
Wizard: only the worker writes the last progress percentage
timliudev Oct 17, 2026
c860db5
Wizard: en/zh strings in one table
timliudev Oct 17, 2026
ad34711
Merge refactor: setup/driver/package/wizard
timliudev Oct 17, 2026
117eb7b
Merge refactor: dynafix split
timliudev Oct 17, 2026
0582a1a
Merge refactor: update/launcher applog
timliudev Oct 17, 2026
125d521
Tests: drop duplicate driver_prep_stage stub after merge
timliudev Oct 17, 2026
3923d63
Docs: align with the refactor; CHANGELOG entry
timliudev Oct 17, 2026
fd9acc6
Docs: refactor record (completed)
timliudev Oct 17, 2026
72c699e
Merge refactor/solid: SOLID refactor (setup/wizard/driver/package spl…
timliudev Oct 17, 2026
ba51eb8
Docs: remove private details from the refactor record
timliudev Oct 17, 2026
8977f01
Shortcuts: bound-check everything appended after the shell folder path
timliudev Oct 17, 2026
92bedd2
Wizard: ignore a WM_JOBDONE that does not name a running job
timliudev Oct 17, 2026
b09b00a
dynafix: state the bounded wait of the loader notification truthfully
timliudev Oct 17, 2026
1a8ba03
Docs: generic wording for the virtual machine tools
timliudev Oct 17, 2026
948ff15
Docs/tests: small stale-reference fixes
timliudev Oct 17, 2026
a176d7a
Release v1.7.2: CHANGELOG and manual
timliudev Oct 17, 2026
657d770
Merge pull request #16 from timliudev/release/v1.7.2
timliudev Oct 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
shell: cmd
run: call tests\build-hardening-tests.cmd || exit /b 1

# Driver tests (src\driver.c, the zip extraction of src\package.c); they use only %TEMP%\drf-drv-<pid>, no system tool is started.
# Driver tests (src\driver.c, the zip reading and staging of src\package.c; the whole-zip extraction lives only in tests\zip_extract_all.h); they use only %TEMP%\drf-drv-<pid>, no system tool is started.
- name: Driver tests
shell: cmd
run: call tests\build-driver-tests.cmd || exit /b 1
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

[繁體中文在下方](#更新紀錄)

## v1.7.2 — 2026-10-18

Internal refactor (no intended behaviour change; see Fixed): `setup.c` is split into topic files in `src\setup\` and `wizard.c` into flow files in `src\wizard\` (each still one compilation unit), `setup.h` is now an umbrella over the `drf_*.h` module headers, the result codes have names in `src\errors.h` (values unchanged), the install options travel in `install_opts` instead of globals, the setup and driver stages share one command-line verb table, the wizard uses a page table and a job table, the launcher and the update check share `src\applog.h` (log lock, clock, value names, verbs), and `dynafix.c` is split into `dynafix_*.inc.c`. Test-only code (COM promotion, whole-zip extraction) moved out of the shipped sources into `tests\`.

Fixed:

- **"Close DynaRun and install" now applies to one install only.** The consent was kept for later attempts: after a cancelled UAC prompt or a failed install, a DynaRun started in the meantime could be ended without asking. The question is now asked again.
- **A failed driver preparation no longer leaves files behind.** The staged driver files and `accepted.txt` in `%ProgramData%\DynaRunFix\driver` are removed when the check, the copy, the boot option or the scheduled task step fails.
- **A very long `%APPDATA%` path no longer overflows a buffer** in the shortcut and taskbar pin code; the folder that does not fit is skipped. The check now also counts what is added after the folder (the taskbar's pinned-items folder and the shortcut file name), which could still overflow for paths of about 200 characters or more; the same check covers the desktop shortcut.
- **The setup wizard ignores a "job finished" window message that its own worker thread did not send.** The message number was used as an index into an internal table without a check, so a stray message could crash the wizard.
- **The download progress bar** is updated by the download thread only (exactly one update per value when the size is unknown).
- **dynafix.dll:** a race between the loader callback and the periodic check that could patch the same hook twice on two threads is fixed.

## v1.7.1 — 2026-10-17

Fixed:
Expand Down Expand Up @@ -496,6 +509,19 @@ Changed and fixed (after a review of v1.4.0):

## 更新紀錄

### v1.7.2 — 2026-10-18

內部重構(不打算改變行為;見「修正」):`setup.c` 依主題拆成 `src\setup\` 內的檔案、`wizard.c` 拆成 `src\wizard\` 內的流程檔(仍是單一編譯單元);`setup.h` 改為 `drf_*.h` 模組標頭的總入口;結果碼在 `src\errors.h` 命名(數值不變);安裝選項以 `install_opts` 傳遞而非全域變數;安裝程式與驅動程式階段共用一張命令列動詞表;精靈改用頁面表與工作表;啟動器與更新檢查共用 `src\applog.h`(log 鎖、時鐘、值名稱、動詞);`dynafix.c` 拆成 `dynafix_*.inc.c`。僅供測試的程式碼(COM 登錄提升、整包 zip 解壓)移出正式原始碼,放到 `tests\`。

修正:

- **「關閉 DynaRun 並安裝」只對一次安裝有效。** 先前同意會留給之後的重試:UAC 被取消或安裝失敗後,期間才啟動的 DynaRun 可能未經詢問就被結束。現在會重新詢問。
- **驅動程式準備失敗時不再留下檔案。** 檢查、複製、開機選項或排程工作任一步失敗時,會移除 `%ProgramData%\DynaRunFix\driver` 內已放置的驅動程式檔與 `accepted.txt`。
- **%APPDATA% 路徑非常長時不再造成緩衝區溢位**(捷徑與工作列釘選程式碼);放不下的資料夾會被略過。檢查現在也計入資料夾之後才加上的部分(工作列釘選項目的資料夾與捷徑檔名),約 200 個字元以上的路徑先前仍可能溢位;桌面捷徑也用同一個檢查。
- **安裝精靈會忽略不是它自己的工作執行緒送出的「工作完成」視窗訊息。** 先前未經檢查就把訊息的數字當成內部表格的索引,雜訊訊息可能使精靈當機。
- **下載進度條**只由下載執行緒更新(大小未知時每個數值只更新一次)。
- **dynafix.dll:** 修正載入回呼與定期檢查之間的競爭,兩個執行緒可能同時修改同一個 hook。

### v1.7.1 — 2026-10-17

修正:
Expand Down
6 changes: 3 additions & 3 deletions docs/FIRST_START.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ text in ANSI-charset fonts is drawn as Latin letters.

## How this was tested

* VirtualBox VMs: Windows 11 (locale changed to zh-TW), Windows 11 installed in zh-TW, Windows 7, Windows XP
* Virtual machines: Windows 11 (locale changed to zh-TW), Windows 11 installed in zh-TW, Windows 7, Windows XP
(fresh install with the official DynaRun installer).
The VMs were driven through `VBoxManage` keyboard/mouse input and screenshots.
The VMs were driven through the virtual machine tools' keyboard/mouse input and screenshots.
* Process Monitor captures filtered to `DynaPro` / `Setup_` events, registry dumps of `HKCU\Software\DynaPro`
before and after the helper.

Expand Down Expand Up @@ -202,5 +202,5 @@ DynaRun 在 ANSI 字元集字型裡的 Big5 文字會變成拉丁字母。

### 測試方法

VirtualBox 虛擬機(Win11 改繁中地區、原生繁中 Win11、Win7、全新 XP),透過 `VBoxManage` 鍵盤/滑鼠操作與截圖;
虛擬機(Win11 改繁中地區、原生繁中 Win11、Win7、全新 XP),透過虛擬機工具的鍵盤/滑鼠操作與截圖;
Process Monitor 只篩選 `DynaPro`/`Setup_` 事件;設定程式執行前後匯出 `HKCU\Software\DynaPro`。
8 changes: 8 additions & 0 deletions docs/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ whenever DynaRun starts its first-time setup helper (normally only on the very f

## What's new

v1.7.2 (released 2026-10-18):
- Fix: a very long `%APPDATA%` path (about 200 characters or more) no longer overflows a buffer in the shortcut and taskbar pin code; the folder that does not fit is skipped.
- Fix: the setup wizard ignores a "job finished" window message that its own worker thread did not send (it could crash the wizard). Also: "Close DynaRun and install" applies to one install only, and a failed driver preparation removes the staged driver files. The rest is an internal source reorganisation without intended changes; see the [changelog](../CHANGELOG.md).

v1.7.1 (released 2026-10-17):
- Fix: a full install with the driver now asks for administrator permission only once. Before, on an administrator account it asked twice (once for the fix, once to prepare the driver), although the documentation said once. The driver pages (download and check, the restart picture) now come before the install; *Install and restart* then installs the fix and prepares the driver in one step, and *Skip* installs the fix without the driver. After the restart an administrator account is not asked again; a standard user still is (administrator password).

Expand Down Expand Up @@ -767,6 +771,10 @@ DynaRun 執行中不會裁剪,所以單次執行期間檔案可能超過 10 MB;
log 只記模組與 API 名稱、不含模組或匯入位址(可能出現視窗與 GDI 控制代碼的值),寫入時不跟隨符號連結或連接點,但可能含有檔案路徑與視窗標題,貼到網路上之前請先檢查。同一個 dll 也修正[首次設定](#首次設定)與 [OneDrive 檔案打不開](#部分-dpr-打不開file-run-properties-全空沒有曲線)的問題。

### 更新內容
v1.7.2(2026-10-18 發行):
- 修正:%APPDATA% 路徑非常長(約 200 個字元以上)時,捷徑與工作列釘選程式碼不再造成緩衝區溢位;放不下的資料夾會被略過。
- 修正:安裝精靈會忽略不是它自己的工作執行緒送出的「工作完成」視窗訊息(先前可能使精靈當機)。另外:「關閉 DynaRun 並安裝」只對一次安裝有效,驅動程式準備失敗時會移除已放置的驅動程式檔。其餘是內部原始碼整理,不打算改變行為;見[更新紀錄](../CHANGELOG.md)。

v1.7.1(2026-10-17 發行):
- 修正:同時安裝驅動程式的完整安裝,現在只會要求一次系統管理員權限。先前在系統管理員帳戶上會問兩次(一次裝修正、一次準備驅動程式),和文件寫的「問一次」不符。驅動程式的頁面(下載與檢查、重新開機選單的圖片)現在排在安裝之前;按「安裝並重新開機」後,一步完成修正的安裝與驅動程式的準備;選「略過」則只安裝修正、不裝驅動程式。重新開機後,系統管理員帳戶不會再被詢問;標準使用者仍會被詢問(要輸入系統管理員密碼)。

Expand Down
64 changes: 64 additions & 0 deletions docs/REFACTOR_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 重構紀錄(已完成,2026-10-18)

依據:2026-10-17 逐行讀完 `src/` 全部模組、`tests/`、`build.cmd` 後擬定的計畫;本文件記錄實際結果。已合併進 `develop`。

## 原則(執行時維持)

- **行為不變**:每一步都是純重構;疑似 bug 另案驗證、另開 commit。
- **小步、可驗證**:每步單獨編譯、跑單元測試與回歸清單(`tests/VM_CHECKLIST.md`)、單獨 commit。
- **跨行程 ABI 不動**:elevated stage 的命令列動詞與參數位置、行程結束碼的數值、log mutex 名稱與格式、`CwpProc` 匯出、`setup.rc` 資源 ID、`DRF_VERSION` 巨集全部維持原樣,只加命名常數。
- **測試仍可 include**:測試靠 `#include "../src/setup.c"`、`driver.c` 取用 static,所以拆檔後各 `.c` 仍是單一編譯單元。

## 決定

維護者的決定:

1. 範圍:P0–P6 全部做,並行進行。
2. 結果碼:只加名稱,數值不變(跨行程 ABI 不變)。
3. 疑似 bug:先驗證,確認有問題的另開 commit 修,不混在重構 commit 裡。
4. 死碼:移到 tests,不留在正式程式碼。

## 根本問題(「改 A 動 B」的來源)

1. 流程靠全域旗標傳遞(`g_close`、`g_pin`、`g_keep`、`g_autostart(_later)`、`g_quiet`),`run_elevated` 暗中依它們附加參數。
2. 隱藏狀態:`g_user_sid`、`g_exe_trusted`、`pMsi*`、`g_tool_ok_code`、`g_other_dir` 等側通道。
3. 結果碼互相重疊(PK_*、RC_*、DRV_E_*、裸數字)。
4. 分派散落:精靈 22 頁、7 個 job,新增一頁要改約 9 處;命令列在 setup.c 與 driver.c 各分派一次。
5. 模式旗標 `g_pre`、`g_driver_only`、`g_fix_done`、`g_drvmode` 交叉決定頁面。
6. 重複邏輯要手動同步(捷徑目錄清單、目錄走訪、啟動行程並等待、log mutex SDDL、zip EOCD 掃描、`update_run`/`update_offer`)。
7. `setup.c` 混了約 8 個領域,`setup.h` 讓所有模組看到全部宣告。

## 實際結果(模組配置)

- **P0 安全網**:`tests/VM_CHECKLIST.md`(VM 回歸清單)、特性測試鎖住命令列解析、`run_elevated` 參數字串與結果碼判斷。
- **P1 基礎層**:`src/errors.h`(結果碼命名,數值不變);`src/setup/util.h`(路徑組合、`run_process`、`dir_walk`、app key 開啟);`src/applog.h`(launcher 與 update 共用 log mutex、SDDL、時鐘與 `Update*` 登錄值名稱)。
- **P2 setup**:`install_opts` 取代全域旗標;`cmdline.h` 動詞表(併入 driver 的動詞);`shortcuts.h` 單一捷徑目錄清單;`trust_ctx` 與 `msi_api_init`。`src/setup.c` 保留入口並 include `src/setup/` 下分檔:`defs.h`、`strings.h`、`util.h`、`trust.h`、`exetime.h`、`procs.h`、`shortcuts.h`、`taskbar.h`、`elevate.h`、`machine.h`、`msi_stage.h`、`userstage.h`、`users.h`、`stage.h`、`uninstall.h`、`cmdline.h`。
- **P3 package / driver**:`package.c` 單一 central directory 讀取器;`driver.c` 側通道改成參數、`prep_locked` 單一出口。`setup.h` 拆成 `drf_app.h`、`drf_util.h`、`drf_package.h`、`drf_driver.h`、`drf_update.h`、`drf_wizard.h`,測試專用宣告在 `drf_package_internal.h`、`drf_driver_internal.h`;`setup.h` 保留為總括 header,`setup_match.h` 為比對輔助。
- **P4 wizard**:job 表、單一 flow 值、頁面表(每頁一個 `enter_*`)、明確的 `wz.result`(結果碼)、`wizard_state` 與 worker 輸入輸出結構、en/zh 字串集中。`src/wizard.c` include `src/wizard/` 下的 `main.h`、`acquire.h`、`driver.h`、`layout.h`、`strings.h`。
- **P5 update**:`update_prompt(policy)` 取代 `update_run`/`update_offer`;launcher 入口拆成 `parse_args`、`elevation_gate`、`start_le`、`start_plain`、`hook_and_finish`。
- **P6 dynafix**:資料表、提示 UI、選項、畫面、PEGRC 移到 `src/dynafix_tables.inc.c`、`dynafix_hint.inc.c`、`dynafix_options.inc.c`、`dynafix_screen.inc.c`、`dynafix_pegrc.inc.c`,由 `src/dynafix.c` include。hook 引擎、`seh_run`、`patch_slot`、`ldr_note`、USBFIX 狀態機、`cwp_work` 順序未動。
- **死碼移入 tests**:`promote_com_in` 等測試專用 COM 輔助(0609115、e66d23d)移到 `tests/promote_com.h`,`zip_extract_all` 移到 `tests/zip_extract_all.h`。

### 與計畫的差異

- P1.3 `applog` 為純 header(`src/applog.h`),`build.cmd` 不需改。
- dynafix 維持單一編譯單元(`.inc.c`),`logtest.c` 與 `build.cmd` 不動;dynafix 的 log 未併入 `applog.h`。
- `setup.c` 仍是單一編譯單元,include 分檔,測試照舊 include 它。

## 疑似 bug:結論

1. `zip_extract` 未呼叫 `crc_init`:**不是 bug**。`zipent` 只來自 `zip_open`/`zip_walk`,它們已呼叫 `crc_init`;仍把 `crc_init` 改成可重複呼叫並由 `zip_extract` 呼叫作為防禦(P3.1)。
2. `g_pkg_log` 常開:**不是 bug**。只有 `driver_fetch` 路徑會寫入;已改成參數(P3.2)。
3. `classify` 的 `pMsi*` 為 NULL:**不是 bug**。`restore`/`unretarget` 只用 `LNK_OURS` 判斷,在 MSI 查詢之前就決定;仍新增 `msi_api_init`(P2.4,由 `classify` 呼叫,只執行一次),所以各路徑(含 uninstall)都會載入 msi.dll。
4. `prep_locked` 提早 return 未清理:**已修**,948ee1f(準備失敗時清除已暫存檔案與 `accepted.txt`)。
5. `peg_ldr_note` 在 loader lock 下呼叫 `logf`/`patch_base`:依維護者決定**不修**。沒有死鎖(具名 mutex 最多等 2 秒+檔案 I/O,不呼叫 LoadLibrary),且 patch 不能延後。但發現相關競態並修正,cb1aa28(loader callback 以非阻塞方式取得 `peg_check` 的 busy 旗標,拿不到就延後)。
6. worker 無鎖寫入 `g_drv_*`、`g_neterr`、`g_hint_*`:**不是 bug**,`job_done` 在 UI 讀取前已 join worker;唯一的良性競態是 `g_lastpct`,改成只有 worker 寫入,1c8498e。
7. `g_close` 設成 TRUE 後不再恢復:**已修**,2a1faa5(「關閉 DynaRun 並安裝」的同意只涵蓋一次安裝 job)。
8. 死碼:移到 tests,0609115(另 e66d23d 移走其餘測試專用 COM 輔助)。
- 額外修正:0791e0e,APPDATA 路徑過長時捷徑/釘選程式碼會溢位,改為略過該資料夾。

## 合併與驗證

- 重構分三條並行線(主程式/setup 與 wizard、dynafix、update),皆從 main 912e3d4 分出,依序合併進 `refactor/solid`(merge commit ad34711、117eb7b、0582a1a);各線主要 commit 為 c860db5、cb1aa28、b4a59b6。125d521 移除合併後重複的 `driver_prep_stage` stub;3923d63 文件對齊。
- 最終驗證(3923d63):單元測試與 dynafix 測試通過,`tests/VM_CHECKLIST.md` 回歸清單通過;其中需手動或需特殊環境的項目未執行(見下)。
- 未驗證:標準使用者相關的手動章節、7.5 redirect(需受信任的自簽憑證)、BitLocker、Win8/7/XP、合併後版本的更新檢查(§8;已在 update 分支驗證)。
2 changes: 1 addition & 1 deletion docs/ROOT_CAUSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Environment where this was analysed:

| | Windows 11 (native) | Windows 7 SP1 (VirtualBox VM) |
| | Windows 11 (native) | Windows 7 SP1 (virtual machine) |
|---|---|---|
| DynaRun V3 | 3.26 | 3.26 (same installer) |
| Screen | 2048x1280 logical, 2 monitors | 2560x1443, 1 monitor |
Expand Down
Loading