diff --git a/CHANGELOG.md b/CHANGELOG.md index d8eaecc..fdcb04c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ [繁體中文在下方](#更新紀錄) +## v1.7.1 — 2026-10-17 + +Fixed: + +- **A full install with the driver asked for administrator permission twice, not once.** Earlier notes (v1.5.0 and the driver documentation) said that an administrator account is asked once; that was not true when the driver was ticked: Windows asked for the install (the fix, with DynaRun's setup first when it was missing) and again for the driver's preparation. Now ONE elevated step does both, so an administrator account gets a single prompt for the whole install and none after the restart (the sign-in task already runs elevated). A standard user is asked for an administrator's password before the restart and, as before, once more after it. The red *Windows Security* "can't verify the publisher" window is not a UAC prompt and still appears twice. + +Changed (setup wizard): + +- **The driver pages come before the install** when the driver is ticked: after the license page (or, when DynaRun V3 is already installed, right after the first page) the wizard shows what the driver step does, looks for / downloads and checks the driver, and shows the restart-menu picture with the button *Install and restart*; that button installs the fix and prepares the driver in one elevated step and restarts the computer. *Skip* on these pages installs the fix without the driver; *Cancel* (or closing the window) on the restart page changes nothing. The page "Done" is not shown when the install goes straight on to the restart; its hints (pin to the taskbar by hand, the warning about the non-Unicode language setting) are shown on the restart page instead. +- If the fix fails, the driver is not prepared and the usual error page appears. If the fix is installed but the driver preparation fails, the driver error page says that the fix itself is installed and points to the Start menu shortcut for trying the driver again. The driver alone (first page with only the driver, `/driver`, the Start menu shortcut) is unchanged: its restart page still reads *Restart now*, and it asks once. +- Internal: the elevated stage (`/machine`, `/full`) takes `/with-driver [/unverified ]` and runs the driver's preparation in the same process after the fix; `/driver-prep` alone is unchanged. + ## v1.7.0 — 2026-10-17 Added (setup wizard): @@ -484,6 +496,18 @@ Changed and fixed (after a review of v1.4.0): ## 更新紀錄 +### v1.7.1 — 2026-10-17 + +修正: + +- **同時安裝驅動程式的完整安裝,系統管理員權限被詢問了兩次,而不是一次。** 先前的說明(v1.5.0 與驅動程式文件)寫「系統管理員帳戶只會問一次」,勾選驅動程式時其實不成立:Windows 為安裝(修正;DynaRun 還沒安裝時先裝它的安裝程式)問一次,為準備驅動程式又問一次。現在由**同一個**提升權限的步驟一次做完,所以系統管理員帳戶在整個安裝只會看到一次提示,重新開機後不會再問(登入時的排程工作本來就以提升的權限執行)。標準使用者在重新開機前要輸入系統管理員密碼,重新開機後和以前一樣再被要求一次。紅色的「Windows 安全性」「無法驗證發行者」視窗不是 UAC 提示,仍然會出現兩次。 + +變更(安裝精靈): + +- **勾選驅動程式時,驅動程式的頁面排在安裝之前:** 授權合約頁之後(DynaRun V3 已安裝時,則是第一頁之後),精靈先說明驅動程式這一步要做什麼、尋找或下載並檢查驅動程式,再顯示重新開機選單的圖片和「安裝並重新開機」按鈕;按下後在同一個提升權限的步驟裡安裝修正、準備驅動程式,然後重新開機。這些頁面的「略過」只安裝修正、不裝驅動程式;重新開機那一頁按「取消」(或關閉視窗)不會改變任何東西。安裝直接進入重新開機時,不會顯示「完成」頁;它的提示(手動釘選到工作列、「非 Unicode 程式的語言」的警告)改在重新開機那一頁顯示。 +- 修正安裝失敗時,不會準備驅動程式,顯示原本的錯誤頁。修正已裝好、但驅動程式的準備失敗時,驅動程式的錯誤頁會說明修正本身已安裝,並指出可用開始功能表的捷徑再試驅動程式。只裝驅動程式的情況(第一頁只提供驅動程式、`/driver`、開始功能表捷徑)沒有改變:重新開機那一頁仍是「重新開機」,而且只問一次。 +- 內部:提升權限的階段(`/machine`、`/full`)可帶 `/with-driver [/unverified ]`,在同一個行程裡於修正之後執行驅動程式的準備;單獨的 `/driver-prep` 沒有改變。 + ### v1.7.0 — 2026-10-17 新增(安裝精靈): diff --git a/README.md b/README.md index 8967d6f..d946b4d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ software (Dyna Pro Dynamometers, S68 and similar rigs) when it runs **natively o - Windows 10 or 11 (the installer also runs on Windows XP and 7; the automatic driver installation needs Windows 10 or 11). - A legally installed DynaRun V3, or the setup password you got from Dyna Pro (the installer can download and install DynaRun V3 for you). -- Administrator permission for the install (Windows asks once). DynaRun itself never runs with more rights than a normal start. +- Administrator permission for the install. On an administrator account Windows asks once for the whole install, the driver included; a standard user types an administrator's password, and again after the restart when the driver is installed. DynaRun itself never runs with more rights than a normal start. ## Install @@ -25,7 +25,7 @@ software (Dyna Pro Dynamometers, S68 and similar rigs) when it runs **natively o SmartScreen may say *"Windows protected your PC"* because the file is not code-signed: click **More info → Run anyway**. 2. Follow the wizard. It installs DynaRun V3 first if it is missing (asking for the setup password from Dyna Pro), then the fix, and points DynaRun's shortcuts at it. 3. **First time on this PC? Also install the Dyna Pro USB driver.** Leave **Also install the Dyna Pro USB driver (one restart needed)** - ticked on the first page (Windows 10 / 11); it needs one restart, where you press **7**. Steps and problems: + ticked on the first page (Windows 10 / 11); it needs one restart, where you press **7**; Windows still asks for permission only once. Steps and problems: [manual: Installing the Dyna Pro USB driver](https://github.com/timliudev/DynaRunFix/blob/main/docs/MANUAL.md#installing-the-dyna-pro-usb-driver) and the [driver guide](https://github.com/timliudev/DynaRunFix/blob/main/docs/DRIVER.md). ## Use @@ -59,7 +59,7 @@ MIT, see [LICENSE](https://github.com/timliudev/DynaRunFix/blob/main/LICENSE). T - Windows 10 或 11(安裝程式也可在 Windows XP、7 執行;自動安裝驅動程式需要 Windows 10 或 11)。 - 合法安裝的 DynaRun V3,或你從 Dyna Pro 取得的安裝密碼(安裝程式可以替你下載並安裝 DynaRun V3)。 -- 安裝時需要系統管理員權限(Windows 會問一次)。DynaRun 本身永遠不會以高於一般啟動的權限執行。 +- 安裝時需要系統管理員權限。使用系統管理員帳戶時,整個安裝(包括驅動程式)Windows 只會問一次;標準使用者要輸入系統管理員密碼,安裝驅動程式時重新開機後還會再問一次。DynaRun 本身永遠不會以高於一般啟動的權限執行。 ### 安裝 @@ -67,7 +67,7 @@ MIT, see [LICENSE](https://github.com/timliudev/DynaRunFix/blob/main/LICENSE). T 因為檔案沒有程式碼簽章,SmartScreen 可能顯示「Windows 已保護您的電腦」:按**其他資訊 → 仍要執行**。 2. 照精靈畫面操作。還沒安裝 DynaRun V3 時會先安裝(會要求 Dyna Pro 給你的安裝密碼),接著安裝修正,並把 DynaRun 的捷徑指向它。 3. **這台電腦第一次使用?還需要安裝 Dyna Pro USB 驅動程式。** 讓精靈第一頁的**同時安裝 Dyna Pro USB 驅動程式(需重新開機一次)**維持勾選(Windows 10 / 11); - 需要重新開機一次,並在選單按 **7**。步驟與疑難排解: + 需要重新開機一次,並在選單按 **7**;Windows 仍然只會詢問一次是否允許變更。步驟與疑難排解: [使用手冊:安裝 Dyna Pro USB 驅動程式](https://github.com/timliudev/DynaRunFix/blob/main/docs/MANUAL.md#安裝-dyna-pro-usb-驅動程式)與[驅動程式指南](https://github.com/timliudev/DynaRunFix/blob/main/docs/DRIVER.md#繁體中文)。 ### 使用 diff --git a/docs/DRIVER.md b/docs/DRIVER.md index f612234..60c3300 100644 --- a/docs/DRIVER.md +++ b/docs/DRIVER.md @@ -31,8 +31,10 @@ available. the first error with **Continue download** (from the part that is already there), **Open website**, **Choose file...** (the zip, or ftdibus.inf in the folder where it is unpacked: the same check follows) and, in the main installer, **Skip**. If Windows says the computer has no network at all, that page comes at once. * If DynaRun V3 and the fix are already installed and only the driver is missing, the installer's first page offers just the driver. -* Windows asks for administrator permission (UAC). On an administrator account that is once; a standard user may be asked for an - administrator's password again after the restart. If BitLocker protection is on (or its status cannot be read), the wizard suspends it until the driver is installed +* Windows asks for administrator permission (UAC) **once** on an administrator account, for the whole installation: in the main installer the same prompt + (on *Install and restart*) installs the fix, installs DynaRun V3 first if the wizard does that too, and prepares the driver; none follows after the restart. A standard user is asked + for an administrator's password before the restart and again after it. The red *Windows Security* "can't verify the publisher" window (below) is not a UAC prompt. In the main installer the + driver pages (download and check, the picture of the restart menu) come before anything is installed, and **Skip** installs the fix without the driver. If BitLocker protection is on (or its status cannot be read), the wizard suspends it until the driver is installed (at most 3 restarts as a safety net, then it is resumed automatically; it is also resumed when the installation finishes or you cancel), sets the one-time advanced boot options and registers a task that continues the wizard when you sign in. While it is suspended, the drive is not protected; if you decide not to go on, cancel in the wizard (or run `/driver-cancel`, see below) so that it is resumed. @@ -205,7 +207,7 @@ DynaRunFix 安裝程式可以幫你做完下面的步驟。除非它說做不到 * 精靈會先找你已經有的「Dyna Pro USB.zip」(它自己先前下載的、精靈所在資料夾、下載資料夾與其下一層、桌面、文件;檔名不限,所以「Dyna Pro USB (1).zip」也算,已經解開的資料夾例如 Downloads\Dyna Pro USB 也算),內容正確就直接使用、不用下載;找不到才從 dynapro.co.uk 下載官方的 zip(不內附)。檢查的是**內容**:Windows 會安裝的 18 個檔案(兩個 INF、它們的兩個 catalog,以及它們所指定的 i386 與 amd64 的 `.sys` / `.dll`)必須各自符合程式內建的 SHA-256;zip 裡的其他檔案(readme、FT Clean、重複的「64-Bit Drivers」資料夾)不看,也只解開這 18 個。Windows 安裝的就是解開並檢查過的那份。 * 如果檔案不同(可能是 Dyna Pro 更新了驅動程式,也可能是檔案損毀或被竄改),精靈會顯示警告頁,列出來源、zip 的 SHA-256 和不同的檔案。只有套件看起來仍是 Dyna Pro 的(18 個檔案都在、bus INF 含 Dyna Pro 的裝置 ID)才會提供「仍要安裝」(不是預設按鈕);否則請用下方的手動方式。選「仍要安裝」只對那一個 zip、這一次安裝有效,並記錄在 `driver.log`。「仍要安裝」生效期間,暫存資料夾裡有 `accepted.txt`(只含實際暫存的那些檔案的 SHA-256),驅動程式步驟結束時刪除。如果你對這台電腦上找到的檔案取消了警告頁,之後的嘗試(包括繼續與重試)都會改從 Dyna Pro 官網下載;在重新開啟精靈之前,不會再提供內容不同的檔案。只有精靈自己找到的副本會這樣被跳過:你用 **選擇檔案…** 選的檔案或資料夾一律照實檢查,不受這個記憶影響。 * DynaRunFix 不驗證驅動程式檔的數位簽章。它只比對檔案的 SHA-256 與程式內建的值,而在「仍要安裝」時檢查 bus INF 是否含 Dyna Pro 的裝置 ID。內容不同的套件來源可不可信,由你自己判斷。 -* Windows 會要求系統管理員權限(UAC)。使用系統管理員帳戶時只會問一次;標準使用者在重新啟動後可能會再被要求輸入系統管理員密碼。若 BitLocker 保護為開啟(或無法讀取其狀態),精靈會暫停它直到驅動程式安裝完成(最多 3 次重新啟動作為保險,之後自動恢復;安裝完成或你按取消時也會恢復),設定一次性的進階開機選項,並登錄一個工作,在你登入後讓精靈繼續。暫停期間磁碟機沒有受到保護;如果你決定不繼續,請在精靈中按取消(或執行 `/driver-cancel`,見下方),讓保護恢復。 +* Windows 會要求系統管理員權限(UAC)。使用系統管理員帳戶時,整個安裝只會問**一次**:在主安裝程式中,按「安裝並重新開機」時的同一次提示,就涵蓋修正的安裝(精靈也要安裝 DynaRun V3 時先裝它)和驅動程式的準備,重新啟動後不會再問。標準使用者在重新啟動前會被要求輸入系統管理員密碼,重新啟動後還會再被要求一次。紅色的「Windows 安全性」「無法驗證發行者」視窗(見下方)不是 UAC 提示。在主安裝程式中,驅動程式的頁面(下載與檢查、重新開機選單的圖片)排在安裝任何東西之前,按 **略過** 就只安裝修正、不裝驅動程式。若 BitLocker 保護為開啟(或無法讀取其狀態),精靈會暫停它直到驅動程式安裝完成(最多 3 次重新啟動作為保險,之後自動恢復;安裝完成或你按取消時也會恢復),設定一次性的進階開機選項,並登錄一個工作,在你登入後讓精靈繼續。暫停期間磁碟機沒有受到保護;如果你決定不繼續,請在精靈中按取消(或執行 `/driver-cancel`,見下方),讓保護恢復。 * 重新啟動後,在啟動選單按 **7**(停用驅動程式強制簽章)。精靈會顯示下面這個畫面,建議先用手機拍下來。圖上會標出「7) 停用驅動程式強制簽章」那一行並寫著 **按 7**。 | 按 7 | diff --git a/docs/MANUAL.md b/docs/MANUAL.md index 9d06110..358eb8f 100644 --- a/docs/MANUAL.md +++ b/docs/MANUAL.md @@ -84,6 +84,9 @@ whenever DynaRun starts its first-time setup helper (normally only on the very f ## What's new +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). + v1.7.0 (released 2026-10-17): - New: a hint on the first page when Dyna Pro's software page publishes a newer DynaRun V3 than the installed one, with *Download new version* (nothing is automatic). For the driver, *Choose file...* also takes the ftdibus.inf of an unpacked folder. - New: when DynaRun and the fix are installed and only the driver is missing, the first page offers just the driver. @@ -114,7 +117,7 @@ All versions: [CHANGELOG.md](../CHANGELOG.md). installer), asks for the **setup password you got from Dyna Pro**, shows a *Check the installer* page (where the file came from, its full path, size, SHA-256 and the MSI's version and manufacturer, in a box you can copy from), then Dyna Pro's license (read from the setup and shown by DynaRunFix itself) and installs DynaRun V3 and the fix only after you accept it (if the license cannot be read from the setup, you must confirm that you accept Dyna Pro's license terms instead). - If DynaRun V3 is already installed, it only installs the fix. If DynaRun V3 is installed in a folder the setup does not find, the first page has *Installed elsewhere...* to point it at `DynaRun V3.exe`. Windows asks once for permission: click **Yes**. + If DynaRun V3 is already installed, it only installs the fix. If DynaRun V3 is installed in a folder the setup does not find, the first page has *Installed elsewhere...* to point it at `DynaRun V3.exe`. Windows asks once for permission: click **Yes**. That one prompt is for the whole install; when the driver is ticked too it covers the driver's preparation as well (the driver pages come before the install, see below). A download that is interrupted is retried by itself (after 1, 2, 4, 8 and 15 seconds; the count starts over whenever data arrived), the page shows the first error of the failed attempts, the *Pause* button stops it cleanly and *Resume* (or, after an error, *Continue download*) carries on from the part that is already there; *Open website* and *Choose file...* remain as ways around it. When Windows says the computer is not connected to a @@ -219,23 +222,23 @@ Up to three options on the first page of the wizard, all on by default (`/quiet` (`TaskbarLayout.xml` in the install folder; `StartLayoutFile` / `LockedStartLayout` under `HKEY_USERS\\Software\Policies\Microsoft\Windows\Explorer`, set by the administrator step): the icon appears after the next sign-out / sign-in. If an organization has already set a layout file it is left alone, - and the last page tells how to pin by hand (right-click the desktop icon → *Show more options* → *Pin to taskbar*). + and the last page tells how to pin by hand (right-click the desktop icon → *Show more options* → *Pin to taskbar*). Without the driver option this is on the last page (*Done*); with it, the install goes straight on to the restart and the same hint is on the page before the restart. A running DynaRun groups under the pinned icon (the launcher shortcuts and DynaRun share an AppUserModelID). The pinning technique for Windows 7 to 10 is the one described by Gee Law ([blog post](https://geelaw.blog/entries/msedge-pins/)); Firefox uses the same approach; no Mozilla code is included. - **Start DynaRun when Windows starts:** the value `DynaRunFix` under `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` starts the launcher (`DynaRunFix.exe /autostart`) at sign-in. Installing again with the box cleared removes it; uninstall removes the Run value for every account, the taskbar policy values of the account that runs the uninstall, of the account the install recorded and of every other account whose taskbar layout file is still ours (their registry hives are loaded briefly for that), and points the pinned launcher shortcuts back at `DynaRun V3.exe`. When the driver option is used as well, the value is **not** written at once: it is noted - (`AutostartPending` under `HKCU\Software\DynaRunFix`) and written when the driver step has ended (installed, failed, cancelled, skipped or the wizard - closed; not while the restart for the driver is still to come), so DynaRun does not start at the sign-in that continues the driver installation. + (`AutostartPending` under `HKCU\Software\DynaRunFix`) and written when the driver step has ended (installed, failed, cancelled or the wizard + closed; not while the restart for the driver is still to come), so DynaRun does not start at the sign-in that continues the driver installation. If you choose *Skip* for the driver, the install itself writes the value. - **Also install the Dyna Pro USB driver (one restart needed).** Shown only on Windows 10/11 and only when the driver is not installed yet. Steps with screenshots: [docs/DRIVER.md](DRIVER.md). In order, the wizard - 1. uses a `Dyna Pro USB.zip` (or the folder it is unpacked in) that is already on the computer (its own earlier download, the setup's folder, Downloads, Desktop, Documents; + 1. (the driver pages come before the install: after the license page, or right after the first page when DynaRun V3 is already installed) uses a `Dyna Pro USB.zip` (or the folder it is unpacked in) that is already on the computer (its own earlier download, the setup's folder, Downloads, Desktop, Documents; any file name) when it holds the right driver files, else downloads it (about 2 MB) over HTTPS from `dynapro.co.uk` only. The check is of the content: each of the 18 files Windows installs (2 INFs, 2 catalogs, the i386 / amd64 `.sys` and `.dll` files they name) must have the SHA-256 built into the program; other files of the zip are ignored and not unpacked. If they differ, a warning page says which and offers "Install anyway" (not the default) when the package still looks like Dyna Pro's; the choice is logged; - 2. asks for administrator permission and saves the setup and the unpacked driver in `%ProgramData%\DynaRunFix` (a folder only administrators - can change); + 2. when you click *Install and restart* (the restart page, with the picture of the menu), asks for administrator permission **once**. In that one elevated step it first installs the fix (after DynaRun V3's own setup, if the wizard installs that too; if this fails, the driver is not touched), then saves the setup and the unpacked driver in `%ProgramData%\DynaRunFix` (a folder only administrators + can change). Items 3 and 4 are part of the same step; 3. **only if BitLocker protection is on or its status cannot be read** - or the drive is still being encrypted or decrypted (also paused) and has a key protector, which Windows reports as "off" although the protector already applies - suspends it (`manage-bde -protectors -disable` for the system drive with `-RebootCount 3`, so protection turns on again by itself after 3 restarts at the latest; the wizard also turns it on again when the @@ -247,12 +250,13 @@ Up to three options on the first page of the wizard, all on by default (`/quiet` `manage-bde -status` and `-protectors -get`, **recovery passwords masked** before anything is written) record what it saw and did; 4. asks Windows for its advanced start-up menu at the next start only (`bcdedit /set {current} onetimeadvancedoptions on`) and registers the scheduled task `DynaRunFix-DriverContinue`, which continues the wizard when you sign in; - 5. restarts the computer when you click *Restart now*. In the menu you press **7** (*Disable driver signature enforcement*); that is off + 5. restarts the computer when that step is done (with the driver alone, started from the first page or by `/driver`, the button is *Restart now* and the step is the driver's preparation only). In the menu you press **7** (*Disable driver signature enforcement*); that is off for that one start only; - 6. after you sign in, installs the driver (`pnputil`); Windows shows its red warning twice (once for each of the two driver files), choose + 6. after you sign in, installs the driver (`pnputil`) with no further UAC prompt on an administrator account (the task runs elevated; a standard user is asked for an administrator's password here). Windows shows its red warning (*Windows Security*, "can't verify the publisher"; this is not UAC) twice (once for each of the two driver files), choose *Install this driver software anyway* each time. The task and the boot option are then removed and BitLocker is turned on again. The last page offers *Start DynaRun*, which starts it as your normal user (not elevated, although that page runs with administrator rights); if that is not possible you are told to use the desktop icon. + *Skip* on the driver pages installs the fix without the driver. If the fix is installed but the driver preparation then fails, the error page says that the fix is installed and the Start menu shortcut can try the driver again. If you do not go on, choose *Cancel* in the wizard or run `DynaRunFix-Setup.exe /driver-cancel`: that takes back the task, the boot option and the BitLocker suspension. Nothing of this is done without ticking the option (or using `/driver`). Other pages: *Check the installer* has an *Open website* button; on Windows 8 and older (Windows 8 / 8.1, Vista / 7, XP) `/driver` shows *The driver @@ -311,9 +315,9 @@ The Dyna Pro dynamometer connects by USB, and Windows needs Dyna Pro's USB drive **With the setup wizard (Windows 10 / 11).** 1. Run `DynaRunFix-Setup.exe` and leave **Also install the Dyna Pro USB driver (one restart needed)** ticked on the first page. The check box is not shown when the driver is already installed or Windows is older than 10. If DynaRun V3 and the fix are already installed, the first page offers just the driver. Later, you can start the same steps from the Start menu shortcut **Install Dyna Pro USB driver** (**安裝 Dyna Pro USB 驅動程式** on a Traditional Chinese Windows) or with `DynaRunFix-Setup.exe /driver`. 2. The wizard first looks for a `Dyna Pro USB.zip` (any file name), or a folder where it was unpacked, that is already on the computer: its own earlier download, the folder the setup runs from, *Downloads* (and one folder below it), *Desktop* and *Documents*. If it finds one that holds the right driver files, it uses it without downloading. Otherwise it downloads the official zip (about 2 MB) from `dynapro.co.uk`. The files are checked by content (SHA-256), not by name. -3. Windows asks for administrator permission (**Yes**). If BitLocker protection is on, the wizard suspends it until the driver is installed (the drive is not protected meanwhile) and turns it on again when the installation ends or is cancelled. -4. Click *Restart now*. In the start-up menu that appears, press **7** (*Disable driver signature enforcement*). Photograph the picture on the wizard's page with your phone first if you like. This only applies to that one start. -5. Sign in. The wizard continues by itself and installs the driver. Windows shows a red warning **twice**; choose **Install this driver software anyway** each time. The last page offers *Start DynaRun*. +3. The wizard shows the page with the picture of the start-up menu (photograph it with your phone if you like). Click *Install and restart* (*Restart now* when only the driver is installed). Windows asks for administrator permission **once** (**Yes**): that one prompt covers installing the fix and preparing the driver, and none follows after the restart. If BitLocker protection is on, the wizard suspends it until the driver is installed (the drive is not protected meanwhile) and turns it on again when the installation ends or is cancelled. *Skip* on the driver pages installs the fix without the driver. +4. The computer restarts. In the start-up menu that appears, press **7** (*Disable driver signature enforcement*). This only applies to that one start. +5. Sign in. The wizard continues by itself and installs the driver (a standard user is asked for an administrator's password here; an administrator account is not asked). Windows shows a red *Windows Security* warning ("can't verify the publisher"; not UAC) **twice**; choose **Install this driver software anyway** each time. The last page offers *Start DynaRun*. **If the warning page appears.** When the files differ from the ones the installer expects (Dyna Pro may have updated the driver, or the file is damaged), the wizard shows a warning with the source, the zip's SHA-256 and the files that differ. *Install anyway* is offered (it is not the default button) only if the package still looks like Dyna Pro's; it applies to that one zip or folder for this one installation. If you **cancel** the warning for a copy the wizard found by itself, it does not use that copy again: later tries (including retry) download the driver from Dyna Pro's website instead. A file you picked yourself with *Choose file...* is always checked as it is. Note that DynaRunFix does not check the driver files' digital signature; it compares the SHA-256 values and, for *Install anyway*, that the bus INF names the Dyna Pro device ID. Whether to trust a package that differs is your decision. @@ -415,7 +419,7 @@ LE gives DynaRun the Big5 code page and charset in every window, including toolt For other DBCS locales (and if LE is missing) `dynafix.dll` creates DynaRun's ANSI-charset fonts with the locale's charset instead (`DYNAFIX_CHARSET`). Nothing in the registry is changed. If the system locale is not Chinese at all, DynaRun's Chinese cannot be shown: set *Language for non-Unicode -programs* to Chinese (Traditional, Taiwan); the Chinese installer says so on its last page when it detects it. +programs* to Chinese (Traditional, Taiwan); the Chinese installer says so on its last page when it detects it (without the driver option on the last page, *Done*; with it, on the page before the restart). ### Garbled Chinese (or other DBCS) text with Windows' UTF-8 option @@ -763,6 +767,9 @@ DynaRun 執行中不會裁剪,所以單次執行期間檔案可能超過 10 MB; log 只記模組與 API 名稱、不含模組或匯入位址(可能出現視窗與 GDI 控制代碼的值),寫入時不跟隨符號連結或連接點,但可能含有檔案路徑與視窗標題,貼到網路上之前請先檢查。同一個 dll 也修正[首次設定](#首次設定)與 [OneDrive 檔案打不開](#部分-dpr-打不開file-run-properties-全空沒有曲線)的問題。 ### 更新內容 +v1.7.1(2026-10-17 發行): +- 修正:同時安裝驅動程式的完整安裝,現在只會要求一次系統管理員權限。先前在系統管理員帳戶上會問兩次(一次裝修正、一次準備驅動程式),和文件寫的「問一次」不符。驅動程式的頁面(下載與檢查、重新開機選單的圖片)現在排在安裝之前;按「安裝並重新開機」後,一步完成修正的安裝與驅動程式的準備;選「略過」則只安裝修正、不裝驅動程式。重新開機後,系統管理員帳戶不會再被詢問;標準使用者仍會被詢問(要輸入系統管理員密碼)。 + v1.7.0(2026-10-17 發行): - 新增:Dyna Pro 的軟體頁面有比已安裝版本更新的 DynaRun V3 時,第一頁會提示並提供「下載新版」(完全不會自動執行)。驅動程式的「選擇檔案…」也可以選已解開資料夾裡的 ftdibus.inf。 - 新增:已安裝 DynaRun 與修正、只缺驅動程式時,第一頁只提供驅動程式。 @@ -788,7 +795,7 @@ v1.6.0(2026-10-17 發行): 2. 照畫面操作。還沒安裝 DynaRun V3 時,會從 [Dyna Pro 官網](https://dynapro.co.uk/Software_Release.htm)下載安裝檔 (「下載」、桌面、「文件」或安裝程式旁邊已經有 DynaRun 安裝檔 zip 或 `Setup.msi` 就直接用),請你輸入 **Dyna Pro 給的安裝密碼**, 先顯示「確認安裝檔」頁(檔案的來源、完整路徑、大小、SHA-256,以及 MSI 的版本與製造商,放在可以複製文字的框裡),再顯示 Dyna Pro 的授權合約(取自安裝檔,由 DynaRunFix 自己顯示),你接受後才安裝 DynaRun V3 和修正(安裝檔裡的合約讀不出來時,必須勾選同意 Dyna Pro 的授權條款才能繼續)。已經裝好 DynaRun V3 時,只會安裝修正。DynaRun V3 裝在安裝程式找不到的資料夾時,第一頁有「已裝在其他位置…」可以指定 `DynaRun V3.exe`。 - Windows 會詢問一次是否允許變更,請按 **是**。 + Windows 會詢問一次是否允許變更,請按 **是**。這是整個安裝只問的一次;同時勾選驅動程式時,它也涵蓋驅動程式的準備(驅動程式的頁面會排在安裝之前,見下方)。 下載中斷時會自動重試(依序等 1、2、4、8、15 秒;只要有資料進來就重新計數),頁面會顯示失敗過程中的第一個錯誤;「暫停」會乾淨地停止, 「繼續」(錯誤之後是「繼續下載」)會從已經下載的部分接續;「開啟官網」與「選擇檔案…」仍然可用。Windows 說電腦完全沒有連上網路時,錯誤頁會立刻出現(不用等重試);主機不回應時 10 秒就放棄。驅動程式走同樣的頁面(先找電腦上現有的,再下載);它的「選擇檔案…」可以選 zip,或已解開它的資料夾裡的 ftdibus.inf。 精靈第一頁最多有三個核取方塊:釘選到工作列、開機時自動啟動 DynaRun,以及(Windows 10/11 且尚未安裝驅動程式時)**同時安裝 Dyna Pro USB 驅動程式(需重新開機一次)**(見下方)。 @@ -859,19 +866,20 @@ DynaRun 的 exe 與程式內容不會被改動(捷徑檔會備份並還原; 所以安裝程式改用微軟的[工作列配置原則](https://learn.microsoft.com/windows/configuration/taskbar/pinned-apps) (安裝資料夾裡的 `TaskbarLayout.xml`;系統管理員那一步會在 `HKEY_USERS\<使用者>\Software\Policies\Microsoft\Windows\Explorer` 設定 `StartLayoutFile`/`LockedStartLayout`):登出再登入後圖示才會出現。組織已經設定配置檔時不會去動它, - 最後一頁會說明手動釘選的方式(在桌面圖示按右鍵 →「顯示其他選項」→「釘選到工作列」)。 + 最後一頁會說明手動釘選的方式(在桌面圖示按右鍵 →「顯示其他選項」→「釘選到工作列」)。沒有勾選驅動程式選項時,這段說明在最後一頁(「完成」);勾選時安裝直接進入重新開機,同樣的說明會出現在重新開機之前的那一頁。 執行中的 DynaRun 會歸在釘選的圖示下(啟動器捷徑和 DynaRun 使用相同的 AppUserModelID)。Windows 7 到 10 的釘選手法是 Gee Law 描述的方式([部落格文章](https://geelaw.blog/entries/msedge-pins/);Firefox 也用同一手法);不含任何 Mozilla 程式碼。 - **開機時自動啟動 DynaRun:** `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` 的 `DynaRunFix` 值在登入時啟動啟動器(`DynaRunFix.exe /autostart`)。 取消勾選後重新安裝會移除它;解除安裝會移除所有帳號的這個值、執行解除安裝的帳號、安裝時記錄的帳號,以及工作列配置檔仍是我們的其他帳號的工作列原則值(為此會短暫載入它們的登錄 hive),並把釘選的啟動器捷徑改回指向 `DynaRun V3.exe`。同時使用驅動程式選項時,這個值**不會**馬上寫入:先記在 `HKCU\Software\DynaRunFix` 的 `AutostartPending`, - 等驅動程式步驟結束(裝好、失敗、取消、略過或關閉精靈;重新開機還沒發生時不算)才寫入,所以 DynaRun 不會在接續驅動程式安裝的那次登入時啟動。 + 等驅動程式步驟結束(裝好、失敗、取消或關閉精靈;重新開機還沒發生時不算)才寫入,所以 DynaRun 不會在接續驅動程式安裝的那次登入時啟動。對驅動程式選「略過」時,由安裝本身寫入這個值。 - **同時安裝 Dyna Pro USB 驅動程式(需重新開機一次)。** 只在 Windows 10/11 且尚未安裝驅動程式時顯示。步驟與畫面見 [docs/DRIVER.md](DRIVER.md#繁體中文)。精靈依序會: - 1. 電腦上已有 `Dyna Pro USB.zip` 或已解開它的資料夾(它自己先前下載的、安裝程式所在資料夾、下載、桌面、文件;檔名不限)且內容正確就直接使用,否則只從 `dynapro.co.uk` 以 HTTPS 下載(約 2 MB)。檢查的是內容:Windows 會安裝的 18 個檔案(2 個 INF、2 個 catalog、它們所指定的 i386 / amd64 `.sys` 與 `.dll`)各自要符合程式內建的 SHA-256;zip 裡的其他檔案不看也不解開。若不同,警告頁會說明是哪些檔案,並在套件看起來仍是 Dyna Pro 的時候提供「仍要安裝」(不是預設按鈕);選擇會被記錄; - 2. 要求系統管理員權限,把安裝程式與解開的驅動程式存放在 `%ProgramData%\DynaRunFix`(只有系統管理員能更改的資料夾); + 1. (驅動程式的頁面排在安裝之前:授權合約頁之後,或已安裝 DynaRun V3 時,在第一頁之後)電腦上已有 `Dyna Pro USB.zip` 或已解開它的資料夾(它自己先前下載的、安裝程式所在資料夾、下載、桌面、文件;檔名不限)且內容正確就直接使用,否則只從 `dynapro.co.uk` 以 HTTPS 下載(約 2 MB)。檢查的是內容:Windows 會安裝的 18 個檔案(2 個 INF、2 個 catalog、它們所指定的 i386 / amd64 `.sys` 與 `.dll`)各自要符合程式內建的 SHA-256;zip 裡的其他檔案不看也不解開。若不同,警告頁會說明是哪些檔案,並在套件看起來仍是 Dyna Pro 的時候提供「仍要安裝」(不是預設按鈕);選擇會被記錄; + 2. 你按「安裝並重新開機」(重新開機選單圖片那一頁)時,**只要求一次**系統管理員權限。在這一個提升權限的步驟裡,先安裝修正(需要時先執行 DynaRun V3 自己的安裝;失敗的話就不處理驅動程式),再把安裝程式與解開的驅動程式存放在 `%ProgramData%\DynaRunFix`(只有系統管理員能更改的資料夾)。第 3、4 項也在同一步驟內; 3. **只有 BitLocker 保護為開啟或無法讀取其狀態時**(或磁碟機仍在加密或解密中,含暫停,且有金鑰保護裝置;Windows 這時會報成「關閉」,但保護裝置已經在作用)才暫停它(對系統磁碟機執行 `manage-bde -protectors -disable` 並加上 `-RebootCount 3`,所以最多 3 次重新啟動後保護會自動恢復;安裝結束或取消時精靈也會讓它恢復, 並在 `HKLM\SOFTWARE\DynaRunFix` 的值 `DriverBitLockerSuspended` 記住這件事)。暫停期間磁碟機沒有受到保護。保護為關閉且磁碟機已完全加密(你自己暫停的),或本來就沒開的,維持原狀。暫停之後會檢查;如果沒有成功(重新開機選單會要求修復金鑰),精靈會顯示警告頁,說明查詢金鑰的方式(aka.ms/myrecoverykey),讓你選「仍要重新開機」或「稍後」(會撤回所有已設定的項目);「查詢修復金鑰」按鈕會開啟那個頁面。精靈的第一個驅動程式頁面會在做任何事之前先說明這一點。`driver.log` 與 `bitlocker-before.txt`(`manage-bde -status` 和 `-protectors -get` 的輸出,**寫入前先遮蔽修復密碼**)記錄看到與做了什麼; 4. 要求 Windows 只在下次開機時顯示進階啟動選單(`bcdedit /set {current} onetimeadvancedoptions on`),並登錄排程工作 `DynaRunFix-DriverContinue`,在你登入後讓精靈繼續; - 5. 你按「重新開機」後重新啟動電腦。你在選單按 **7**(停用驅動程式強制簽章);它只在那一次開機期間關閉; - 6. 登入後安裝驅動程式(`pnputil`);Windows 會跳出紅色警告兩次(兩個驅動程式檔各一次),每次都請選「仍然安裝此驅動程式軟體」。接著移除工作與開機選項,BitLocker 也恢復。最後一頁提供「開始使用 DynaRun」,以你的一般使用者身分啟動(不是提升權限,儘管那一頁是以系統管理員權限執行);做不到時會請你改用桌面圖示。 + 5. 上述步驟完成後重新啟動電腦(只裝驅動程式時,從第一頁或 `/driver` 開始,按鈕是「重新開機」,那一步只準備驅動程式)。你在選單按 **7**(停用驅動程式強制簽章);它只在那一次開機期間關閉; + 6. 登入後安裝驅動程式(`pnputil`),系統管理員帳戶不會再出現 UAC 提示(排程工作以提升的權限執行;標準使用者這時會被要求輸入系統管理員密碼);Windows 會跳出紅色警告(「Windows 安全性」的「無法驗證發行者」視窗,不是 UAC)兩次(兩個驅動程式檔各一次),每次都請選「仍然安裝此驅動程式軟體」。接著移除工作與開機選項,BitLocker 也恢復。最後一頁提供「開始使用 DynaRun」,以你的一般使用者身分啟動(不是提升權限,儘管那一頁是以系統管理員權限執行);做不到時會請你改用桌面圖示。 + 在驅動程式的頁面按「略過」,就只安裝修正、不裝驅動程式。修正裝好、但驅動程式的準備失敗時,錯誤頁會說明修正已安裝,之後可用開始功能表的捷徑再試驅動程式。 不繼續的話,請在精靈按「取消」,或執行 `DynaRunFix-Setup.exe /driver-cancel`:它會撤回工作、開機選項與 BitLocker 暫停。沒有勾選該選項(或使用 `/driver`)就不會做這些事。 其他頁面:「確認安裝檔」頁有「開啟官網」按鈕;在 Windows 8 與更舊的版本(Windows 8 / 8.1、Vista / 7、XP)上,`/driver` 會顯示「驅動程式沒有安裝」,附上該版 Windows 的手動步驟與「開啟手動安裝說明」按鈕;驅動程式已經安裝時會顯示「驅動程式已安裝」。驅動程式搜尋與你的選擇會記錄在 `%TEMP%\DynaRunFix-setup.log`。 @@ -906,9 +914,9 @@ Dyna Pro 測功機以 USB 連接,Windows 需要 Dyna Pro 的 USB 驅動程式 **使用安裝精靈(Windows 10 / 11)。** 1. 執行 `DynaRunFix-Setup.exe`,讓第一頁的**同時安裝 Dyna Pro USB 驅動程式(需重新開機一次)**維持勾選。驅動程式已安裝,或 Windows 版本早於 10 時,不會顯示這個核取方塊。DynaRun V3 與修正都已安裝時,第一頁只提供驅動程式。之後也可以用開始功能表捷徑「安裝 Dyna Pro USB 驅動程式」或 `DynaRunFix-Setup.exe /driver` 進行同樣的步驟。 2. 精靈會先找電腦上已有的 `Dyna Pro USB.zip`(檔名不限)或已解壓縮的資料夾:它自己先前的下載、安裝程式所在的資料夾、「下載」(及其下一層資料夾)、桌面與「文件」。找到內容正確的驅動程式檔案就直接使用,不再下載;否則從 `dynapro.co.uk` 下載官方 zip(約 2 MB)。檢查的是檔案內容(SHA-256),不是檔名。 -3. Windows 要求系統管理員權限時按**是**。若 BitLocker 保護已開啟,精靈會暫停它直到驅動程式裝好(這段期間磁碟機沒有受到保護),並在安裝結束或取消時恢復。 -4. 按「立即重新開機」。在出現的啟動選單按 **7**(停用驅動程式強制簽章)。可以先用手機拍下精靈頁面上的圖。這只在那一次開機有效。 -5. 登入後精靈會自動繼續並安裝驅動程式。Windows 會跳出紅色警告**兩次**,每次都選「仍然安裝此驅動程式軟體」。最後一頁提供「啟動 DynaRun」。 +3. 精靈會顯示啟動選單圖片的那一頁(可以先用手機拍下來)。按「安裝並重新開機」(只裝驅動程式時是「重新開機」)。Windows 要求系統管理員權限時按**是**,**只會問一次**:這一次同時涵蓋修正的安裝和驅動程式的準備,重新開機後不會再問。若 BitLocker 保護已開啟,精靈會暫停它直到驅動程式裝好(這段期間磁碟機沒有受到保護),並在安裝結束或取消時恢復。在驅動程式的頁面按「略過」,就只安裝修正、不裝驅動程式。 +4. 電腦重新開機。在出現的啟動選單按 **7**(停用驅動程式強制簽章)。這只在那一次開機有效。 +5. 登入後精靈會自動繼續並安裝驅動程式(標準使用者這時會被要求輸入系統管理員密碼,系統管理員帳戶不會)。Windows 會跳出紅色「Windows 安全性」警告(「無法驗證發行者」,不是 UAC)**兩次**,每次都選「仍然安裝此驅動程式軟體」。最後一頁提供「啟動 DynaRun」。 **出現警告頁時。** 檔案與安裝程式預期的不同(Dyna Pro 可能更新了驅動程式,或檔案已損壞)時,精靈會顯示警告,列出來源、zip 的 SHA-256 與不同的檔案。只有套件看起來仍是 Dyna Pro 的才會提供「仍然安裝」(不是預設按鈕),且只適用於那一個 zip 或資料夾、那一次安裝。若你對精靈自己找到的副本**取消**警告,之後(包括重試)不會再使用該副本,而是改從 Dyna Pro 官網下載。你用「選擇檔案…」自己選的檔案則一律照原樣檢查。請注意 DynaRunFix 不檢查驅動程式檔案的數位簽章;它比對 SHA-256,並且在「仍然安裝」時檢查 bus INF 是否含有 Dyna Pro 的裝置 ID。是否信任不同的套件由你自己決定。 @@ -979,7 +987,7 @@ Windows 以英文安裝、之後才把系統地區改成中文(台灣)時,`HKLM\ 系統地區是繁體中文時,啟動器偵測到這種情況就改用 Locale Emulator 啟動 DynaRun(照常掛上 `dynafix.dll`), 所有視窗(含工具提示和 OCX 控制項)都以 Big5 字碼頁與字元集顯示。其他 DBCS 地區(或找不到 LE 時)則由 `dynafix.dll` 只在 DynaRun 內把 ANSI 字元集字型改用該地區的字元集建立(`DYNAFIX_CHARSET`)。不改登錄。 -系統地區根本不是中文時無法顯示 DynaRun 的中文,請把「非 Unicode 程式的語言」設為「中文(繁體,台灣)」;中文版安裝程式偵測到時會在最後一頁提示。 +系統地區根本不是中文時無法顯示 DynaRun 的中文,請把「非 Unicode 程式的語言」設為「中文(繁體,台灣)」;中文版安裝程式偵測到時會在最後一頁提示(沒有勾選驅動程式選項時在最後一頁「完成」;勾選時在重新開機之前的那一頁)。 ### 開啟系統 UTF-8 選項時中文亂碼 「地區 → 系統管理 → 變更系統地區設定 → Beta:使用 Unicode UTF-8 提供全球語言支援」開啟時,系統 ANSI 字碼頁是 65001,VB6 程式的中文會變亂碼。 diff --git a/src/driver.c b/src/driver.c index c959356..5974ba1 100644 --- a/src/driver.c +++ b/src/driver.c @@ -1256,6 +1256,14 @@ int driver_prep(const WCHAR *zip, const WCHAR *accept) return run_elevated(args, NULL); } +// Called by the elevated install stage (setup.c, /machine /full ... /with-driver): the driver's preparation in the same process as the fix, so that +// one UAC prompt serves both. sid: the user the stage was started for. +int driver_prep_stage(const WCHAR *sid, const WCHAR *zip, const WCHAR *accept) +{ + if (!is_admin()) return 1; + return prep_locked(sid, zip, accept); +} + int driver_bitlocker(void) { WCHAR dr[4]; int ps; bde_info bi; diff --git a/src/setup.c b/src/setup.c index a987147..f0141b3 100644 --- a/src/setup.c +++ b/src/setup.c @@ -16,6 +16,9 @@ // DynaRunFix-Setup.exe /driver the Dyna Pro USB driver step on its own (driver.c; the wizard's last page) // DynaRunFix-Setup.exe /driver-cancel undo the driver step's preparation (task, start-up menu option, BitLocker) // /driver-prep, /driver-install, /driver-continue the driver step's own stages (elevated, or started by its scheduled task) +// /machine ... /with-driver [/unverified ] (also /full) the elevated stage prepares the driver (driver.c, prep) right after the +// fix, in the same process: one UAC prompt for the fix and the driver; the exit code is the fix's if it +// failed, else the driver's (0, DRV_E_*, DRV_W_BDE) // // Install, in two stages so that per-user changes land in the right profile even when an // administrator's credentials are typed into the UAC prompt: @@ -2126,48 +2129,65 @@ BOOL fix_current(void) return exists(g_launcher) && exists(cat3(d, g_dir, L"\\dynafix.dll", NULL)); } -int install_fix(void) +// The wizard's one elevated stage may do the driver's preparation too (zip != NULL; see driver_prep_stage): the fix and the driver then share ONE UAC prompt. +// The result: the fix's failure code, or, when the fix is installed (user stage done), 0 or the driver's code (DRV_E_*, DRV_W_BDE: >= DRV_E_HASH). +#define FIX_DONE(rc) ((rc) == 0 || (rc) >= DRV_E_HASH) + +static void add_driver_args(WCHAR *args, const WCHAR *zip, const WCHAR *accept) // the command line of the elevated stage { - static WCHAR sid[200], args[600]; int rc; + if (!zip) return; + lstrcatW(args, L" /with-driver \""); lstrcatW(args, zip); lstrcatW(args, L"\""); + if (accept && accept[0]) { lstrcatW(args, L" /unverified "); lstrcatW(args, accept); } +} + +int install_fix_driver(const WCHAR *zip, const WCHAR *accept) +{ + static WCHAR sid[200], args[2 * MAX_PATH + 400]; int rc; if (!user_sid(sid, 200)) return 1; if (running_early(L"install (before elevation)")) return RC_RUNNING; // before the UAC prompt; /quiet without /close ends here CoInitialize(NULL); - if (is_admin()) rc = machine_install(sid); + if (is_admin()) { rc = machine_install(sid); if (!rc && zip) rc = driver_prep_stage(sid, zip, accept); } else { wsprintfW(args, L"/machine %s \"%s\"", sid, g_exe); + add_driver_args(args, zip, accept); if ((rc = run_elevated(args, NULL)) == 2) { msg(no_admin(), MB_ICONWARNING); return 2; } } - if (rc) return rc; + if (!FIX_DONE(rc)) return rc; user_stage(); - return 0; + return rc; } -int install_all(const WCHAR *msi) +int install_fix(void) { return install_fix_driver(NULL, NULL); } + +int install_all_driver(const WCHAR *msi, const WCHAR *zip, const WCHAR *accept) { - static WCHAR sid[200], args[MAX_PATH + 300]; int rc; + static WCHAR sid[200], args[2 * MAX_PATH + 400]; int rc; if (!user_sid(sid, 200)) return 1; if (running_early(L"full install (before elevation)")) return RC_RUNNING; CoInitialize(NULL); pkg_prepare_documents(msi); // as this user, before the SYSTEM-side install (error 1305 otherwise) - if (is_admin()) rc = machine_full(sid, msi); + if (is_admin()) { rc = machine_full(sid, msi); if (!rc && zip) rc = driver_prep_stage(sid, zip, accept); } else { wsprintfW(args, L"/full %s \"%s\"", sid, msi); + add_driver_args(args, zip, accept); rc = run_elevated(args, NULL); } - if (rc == 3) { // over-the-shoulder elevation: setup as this user, then the fix + if (rc == 3) { // over-the-shoulder elevation: setup as this user, then the fix (and the driver) rc = run_msiexec(msi); if (rc == ERROR_INSTALL_USEREXIT) return 2; if (rc && rc != ERROR_SUCCESS_REBOOT_REQUIRED) return 4; if (!locate_dynarun()) return 5; - return install_fix(); + return install_fix_driver(zip, accept); } if (rc == 2) return 2; - if (rc) return rc; + if (!FIX_DONE(rc)) return rc; locate_dynarun(); user_stage(); - return 0; + return rc; } +int install_all(const WCHAR *msi) { return install_all_driver(msi, NULL, NULL); } + // The uninstall question's Yes / No buttons become "Fix only" / "Remove all". static HHOOK g_cbt; static LRESULT CALLBACK relabel(int code, WPARAM w, LPARAM l) @@ -2298,7 +2318,7 @@ void WinMainCRTStartup(void) { typedef BOOL (WINAPI *SetDefaultDllDirectories_t)(DWORD); SetDefaultDllDirectories_t sdd = (SetDefaultDllDirectories_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDefaultDllDirectories"); - int argc, i, rc; BOOL pin = FALSE; WCHAR **argv; + int argc, i, rc; BOOL pin = FALSE; WCHAR **argv; const WCHAR *dzip = NULL, *daccept = NULL; if (sdd) sdd(0x800); // LOAD_LIBRARY_SEARCH_SYSTEM32: no DLL is searched for in the exe's folder or the current folder argv = CommandLineToArgvW(GetCommandLineW(), &argc); g_zh = PRIMARYLANGID(GetUserDefaultUILanguage()) == LANG_CHINESE; @@ -2310,15 +2330,19 @@ void WinMainCRTStartup(void) else if (!lstrcmpiW(argv[i], L"/noautostart")) g_autostart = FALSE; else if (!lstrcmpiW(argv[i], L"/pin")) pin = TRUE; else if (!lstrcmpiW(argv[i], L"/keep")) g_keep = TRUE; + else if (i >= 4 && !lstrcmpiW(argv[i], L"/with-driver") && i + 1 < argc) dzip = argv[++i]; // after the SID and the path: see install_fix_driver + else if (i >= 4 && !lstrcmpiW(argv[i], L"/unverified") && i + 1 < argc) { if (lstrlenW(argv[i + 1]) == 64) daccept = argv[i + 1]; i++; } } if (argc >= 2 && (!lstrcmpiW(argv[1], L"/machine") || !lstrcmpiW(argv[1], L"/full"))) g_pin = pin; // the elevated stage: as asked if (argc >= 4 && !lstrcmpiW(argv[1], L"/machine")) { lstrcpynW(g_exe, argv[3], MAX_PATH); CoInitialize(NULL); rc = machine_install(argv[2]); + if (!rc && dzip) rc = driver_prep_stage(argv[2], dzip, daccept); } else if (argc >= 4 && !lstrcmpiW(argv[1], L"/full")) { CoInitialize(NULL); rc = machine_full(argv[2], argv[3]); + if (!rc && dzip) rc = driver_prep_stage(argv[2], dzip, daccept); } else if (argc >= 2 && !lstrcmpiW(argv[1], L"/unmachine")) { reg_str(HKEY_LOCAL_MACHINE, APPKEY, L"DynaRunExe", g_exe, MAX_PATH, 0); CoInitialize(NULL); diff --git a/src/setup.h b/src/setup.h index 32220af..eab6b84 100644 --- a/src/setup.h +++ b/src/setup.h @@ -29,6 +29,10 @@ BOOL locate_dynarun(void); // fills g_exe from the registry or void start_dynarun(void); // the wizard's "Start DynaRun": through our shortcut, like a double click int install_fix(void); // DynaRun is installed: elevated stage + user shortcuts. 0 ok, 2 cancelled int install_all(const WCHAR *msi); // runs the DynaRun MSI, then install_fix's work. 0 ok, 2 cancelled +// The same, and the driver's preparation (driver_prep) in the SAME elevated stage: one UAC prompt for both. zip/accept as for driver_prep. +// 0 ok; 2 cancelled; another small code: the fix failed (the driver was not touched); >= DRV_E_HASH: the fix is installed, the driver step gave this code (DRV_E_*, DRV_W_BDE). +int install_fix_driver(const WCHAR *zip, const WCHAR *accept); +int install_all_driver(const WCHAR *msi, const WCHAR *zip, const WCHAR *accept); // shared with driver.c void delete_tree(const WCHAR *dir, const WCHAR *keep, int depth); // a link is removed itself, never followed; in-use files go at the next restart BOOL same_file(const WCHAR *a, const WCHAR *b); @@ -149,6 +153,7 @@ const WCHAR *driver_pinned_sha256(void); // the SHA-256 of the zip this progr void driver_forget(const WCHAR *zip); // deletes the zip when it is our own cache file in %TEMP%\DynaRunFix (a refused download), never a file of the user's BOOL driver_partial(DWORD *have); // a partial driver download that driver_fetch can continue; *have: bytes so far int driver_prep(const WCHAR *zip, const WCHAR *accept); // elevated: stage the driver, arm the restart menu and the task (zip "-": the staged copy); 0 or DRV_E_*, 2 = UAC cancelled +int driver_prep_stage(const WCHAR *sid, const WCHAR *zip, const WCHAR *accept); // elevated, inside the install stage (setup.c): driver_prep for sid, no further elevation int driver_bitlocker(void); // BitLocker protection of the system drive, not elevated: 1 on, 0 off / none, -1 cannot be told (needs administrator rights) int driver_install(void); // elevated: pnputil, then clean up. 0 or DRV_E_*, 2 = UAC cancelled int driver_cancel(void); // elevated: task, restart menu and BitLocker suspension back. 2 = UAC cancelled diff --git a/src/wizard.c b/src/wizard.c index d491f01..8cb9ddc 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -44,6 +44,9 @@ static DWORD g_neterr, g_total; static BOOL g_paused, g_pause_req; // download paused (worker ended, .part kept) / pause asked, worker still stopping static int g_hint; // DynaRun update hint (pkg_update_hint): 0 none, 1 a newer version is published, 2 the site's zip differs from the last download static WCHAR g_hint_inst[40], g_hint_new[40]; // the installed and the published version (hint 1) +static BOOL g_pre; // the driver is ticked in the main flow: its package is fetched and checked BEFORE the install, and the one elevated stage installs the fix and prepares the driver (one UAC prompt) +static int g_inst_job; // the install job (JOB_INSTALL_ALL / JOB_INSTALL_FIX) that waits for the driver package while g_pre +static BOOL g_fix_done; // g_pre: the fix is installed (the driver step after it may still have failed) static BOOL g_driver_only; // DynaRun and its fix are installed (this version) and only the driver is missing: the first page offers just that static BOOL g_checking, g_marquee, g_drv_allow; // the non-pausable "checking" phase / marquee bar (size unknown) / the user chose "install anyway" for a zip with another hash static int g_drv_how; // DRV_SRC_*: the driver zip was downloaded, or found on this computer (nothing downloaded) @@ -309,7 +312,7 @@ static int place_image(int x, int y, int w, int ah) // The "Start DynaRun" button is offered only when DynaRun is installed here and our launcher is in place (g_exe comes from locate_dynarun, which // the wizard runs at start in every mode, so this also holds in the process the sign-in task starts after the restart; g_launcher from init_paths). -// The driver step may be skipped (back to the end of the install) only in the main install flow, not when it is the whole job (the shortcut, /driver, or the driver-only first page). +// The driver step may be skipped (the fix is installed without it) only in the main install flow, not when it is the whole job (the shortcut, /driver, or the driver-only first page). static BOOL can_skip_driver(void) { return g_drvmode == DRV_MODE_NONE && !g_driver_only; } // The line about a newer DynaRun on the first page, and its button. A hint only: nothing happens unless the button is clicked. @@ -335,6 +338,24 @@ static void cat_to(WCHAR *d, int cap, const WCHAR *s) if (n < cap - 1) lstrcpynW(d + n, s, cap - n); } +// What is said about the taskbar pin (g_pinresult, set by the user stage) and about DynaRun's Chinese text: on the page "Done" and, when the driver goes with +// the install (g_fix_done: the page "Done" is skipped), on the restart page. +static void pin_hint(WCHAR *b) +{ + if (g_pinresult == 2) lstrcatW(b, T(L"\n\nDynaRun will appear on the taskbar after you sign out and back in.", L"\n\n登出再登入後,DynaRun 會出現在工作列上。")); + if (g_pinresult == 3) lstrcatW(b, os_build() >= 22000 + ? T(L"\n\nTo pin it to the taskbar: right-click the \"DynaRun V3\" icon on the desktop → Show more options → Pin to taskbar.", + L"\n\n要釘選到工作列:在桌面「DynaRun V3」圖示上按右鍵 →「顯示其他選項」→「釘選到工作列」。") + : T(L"\n\nTo pin it to the taskbar: right-click the \"DynaRun V3\" icon on the desktop → Pin to taskbar.", + L"\n\n要釘選到工作列:在桌面「DynaRun V3」圖示上按右鍵 →「釘選到工作列」。")); +} +static void acp_warning(void) +{ + if (g_zh && legacy_acp() != 950) // DynaRun's Chinese is Big5: only a zh-TW system locale shows it everywhere + status(L"注意:這台電腦的「非 Unicode 程式的語言」不是中文(台灣),DynaRun 的中文可能會變成亂碼。\n" + L"請到「設定 → 時間與語言 → 語言與地區 → 系統管理語言設定 → 變更系統地區設定」選「中文(繁體,台灣)」,再重新開機。", TRUE); +} + static void set_page(int p) { static WCHAR b[2600]; @@ -488,22 +509,12 @@ static void set_page(int p) L"The first start asks for your dynamometer model. If Windows asks whether to allow changes, click \"Yes\".", L"全部安裝完成。\n\n以後照常點桌面上的「DynaRun V3」圖示啟動即可。\n\n" L"第一次啟動時會要你選擇馬力機型號;如果 Windows 詢問「是否允許變更」,請按「是」。")); - if (g_pinresult == 2) lstrcatW(b, T(L"\n\nDynaRun will appear on the taskbar after you sign out and back in.", L"\n\n登出再登入後,DynaRun 會出現在工作列上。")); - if (g_pinresult == 3) lstrcatW(b, os_build() >= 22000 - ? T(L"\n\nTo pin it to the taskbar: right-click the \"DynaRun V3\" icon on the desktop → Show more options → Pin to taskbar.", - L"\n\n要釘選到工作列:在桌面「DynaRun V3」圖示上按右鍵 →「顯示其他選項」→「釘選到工作列」。") - : T(L"\n\nTo pin it to the taskbar: right-click the \"DynaRun V3\" icon on the desktop → Pin to taskbar.", - L"\n\n要釘選到工作列:在桌面「DynaRun V3」圖示上按右鍵 →「釘選到工作列」。")); - if (g_autostart) lstrcatW(b, g_drv ? T(L"\n\nDynaRun will start automatically when you sign in, once the driver is installed.", L"\n\n驅動程式安裝完成後,以後開機登入時會自動啟動 DynaRun。") - : T(L"\n\nDynaRun will start automatically when you sign in.", L"\n\n以後開機登入後會自動啟動 DynaRun。")); - if (g_drv) lstrcatW(b, T(L"\n\nNext: the Dyna Pro USB driver, so that this computer can talk to the dynamometer.", L"\n\n下一步:安裝 Dyna Pro USB 驅動程式,電腦才能和馬力機連線。")); + pin_hint(b); + if (g_autostart) lstrcatW(b, T(L"\n\nDynaRun will start automatically when you sign in.", L"\n\n以後開機登入後會自動啟動 DynaRun。")); lstrcatW(b, T(L"\n\nIf DynaRun's screen ever looks wrong, close DynaRun and start it again.", L"\n\n如果 DynaRun 的畫面顯示不正常,關掉 DynaRun 再開一次即可。")); text(ID_BODY, b); - if (g_drv) buttons(T(L"Next", L"下一步"), T(L"Close", L"關閉"), NULL); - else buttons(T(L"Start DynaRun", L"開始使用 DynaRun"), T(L"Close", L"關閉"), NULL); - if (g_zh && legacy_acp() != 950) // DynaRun's Chinese is Big5: only a zh-TW system locale shows it everywhere - status(L"注意:這台電腦的「非 Unicode 程式的語言」不是中文(台灣),DynaRun 的中文可能會變成亂碼。\n" - L"請到「設定 → 時間與語言 → 語言與地區 → 系統管理語言設定 → 變更系統地區設定」選「中文(繁體,台灣)」,再重新開機。", TRUE); + buttons(T(L"Start DynaRun", L"開始使用 DynaRun"), T(L"Close", L"關閉"), NULL); + acp_warning(); break; case P_ERROR: text(ID_TITLE, T(L"Something went wrong", L"發生問題")); @@ -512,7 +523,7 @@ static void set_page(int p) break; case P_DRV_INTRO: text(ID_TITLE, T(L"Install the Dyna Pro USB driver", L"安裝 Dyna Pro USB 驅動程式")); - text(ID_BODY, T(L"Windows needs Dyna Pro's USB driver to talk to the dynamometer.\n\nThis program will:\n" + lstrcpyW(b, T(L"Windows needs Dyna Pro's USB driver to talk to the dynamometer.\n\nThis program will:\n" L" 1. download the driver from the Dyna Pro website (dynapro.co.uk, about 2 MB)\n" L" 2. restart the computer once: a menu appears, press 7 on the keyboard\n" L" 3. come back by itself after you sign in and finish the installation\n\n" @@ -527,6 +538,9 @@ static void set_page(int p) L"廠商封裝中的驅動程式設定檔(INF)不在隨附的 Microsoft 簽署目錄檔中,Windows 無法驗證,所以只有在這一次開機暫時關閉「驅動程式簽章檢查」時才肯安裝;" L"下次重新開機會自動恢復。\n\n" L"如果這台電腦有啟用 BitLocker,保護會暫停到驅動程式安裝完成為止,之後會自動恢復(最多經過 3 次重新開機)。")); + if (g_pre) lstrcatW(b, T(L"\n\nDynaRun's fix is installed in the same step, just before the restart, so Windows asks for permission only once.", + L"\n\nDynaRun 的修正會在同一步、重新開機之前一起安裝,所以 Windows 只會詢問一次是否允許變更。")); + text(ID_BODY, b); buttons(T(L"Next", L"下一步"), can_skip_driver() ? T(L"Skip", L"略過") : T(L"Cancel", L"取消"), NULL); if (g_note[0]) status(g_note, TRUE); break; @@ -543,6 +557,8 @@ static void set_page(int p) lstrcatW(b, t); } if (!g_drv_allow && (g_drv_how & DRV_ZIPDIFF)) lstrcatW(b, T(L"The zip differs from the known version, but the driver files are identical: it can be installed.\n\n", L"壓縮檔和已知版本不同,但驅動程式檔案相同,可以安裝。\n\n")); + if (g_pre) lstrcatW(b, T(L"Click \"Install and restart\": DynaRun's fix is installed and the driver is prepared in one step (Windows asks for permission once), then the computer restarts.\n\n", + L"按「安裝並重新開機」後,會一次完成 DynaRun 修正的安裝和驅動程式的準備(Windows 只會詢問一次是否允許變更),接著電腦重新開機。\n\n")); lstrcatW(b, T(L"Tip: take a photo of this page with your phone.\nSave your work in other programs before you restart.", L"建議用手機拍下這一頁。\n按「重新開機」前請先存好其他程式的資料。")); if (bl > 0) lstrcatW(b, T(L"\n\nThis computer uses BitLocker: protection is suspended for the restart and turned on again by itself after the driver is installed.", @@ -552,7 +568,8 @@ static void set_page(int p) text(ID_BODY, b); } show_image(0); - buttons(T(L"Restart now", L"重新開機"), T(L"Later", L"稍後"), NULL); + if (g_pre) buttons(T(L"Install and restart", L"安裝並重新開機"), T(L"Cancel", L"取消"), NULL); // nothing is installed yet + else buttons(T(L"Restart now", L"重新開機"), T(L"Later", L"稍後"), NULL); if (g_note[0]) status(g_note, TRUE); break; case P_DRV_HASH: { // a driver zip that is not the file this program knows: the user decides @@ -628,14 +645,17 @@ static void set_page(int p) break; case P_DRV_REBOOT: text(ID_TITLE, g_drv_noreboot ? T(L"Please restart the computer", L"請重新開機") : T(L"Restarting", L"即將重新開機")); - text(ID_BODY, g_drv_noreboot + lstrcpyW(b, g_drv_noreboot ? T(L"Everything is ready, but Windows would not restart by itself.\n\nPlease restart the computer yourself (Start, the power button, Restart). " L"When the menu appears, press 7. After you sign in, this program continues by itself.", L"都準備好了,但 Windows 沒有自動重新開機。\n\n請自己重新開機(開始 → 電源 → 重新啟動)。出現選單時請按 7;登入後本程式會自動繼續。") : T(L"The computer restarts now.\n\nWhen the menu appears, press 7. After you sign in, this program continues by itself.\n\n" L"If the computer does not restart (a program is waiting for you), save your work and restart it yourself.", L"電腦即將重新開機。\n\n出現選單時請按 7;登入後本程式會自動繼續。\n\n如果電腦沒有重新開機(有程式在等你回應),請存好資料後自己重新開機。")); + if (g_fix_done) pin_hint(b); // the fix was installed with the driver: the hints of the page "Done", which is skipped + text(ID_BODY, b); buttons(T(L"Close", L"關閉"), NULL, NULL); + if (g_fix_done) acp_warning(); break; case P_DRV_RETRY: text(ID_TITLE, T(L"7 was not pressed", L"剛才沒有按到 7")); @@ -716,8 +736,8 @@ static DWORD WINAPI job_proc(LPVOID unused) } break; case JOB_EXTRACT: rc = pkg_extract_checked(&g_zip, g_pw, g_msi, 400UL * 1024UL * 1024UL, on_progress, &g_cancel); SecureZeroMemory(g_pw, sizeof(g_pw)); break; // a size cap, and a free target (shared with the driver) // the password is not needed any more - case JOB_INSTALL_ALL: rc = install_all(g_msi); break; - case JOB_INSTALL_FIX: rc = install_fix(); break; + case JOB_INSTALL_ALL: rc = g_pre ? install_all_driver(g_msi, g_drvzip, g_drv_allow ? g_drv_hex : NULL) : install_all(g_msi); break; // g_pre: the driver's preparation in the same elevated stage + case JOB_INSTALL_FIX: rc = g_pre ? install_fix_driver(g_drvzip, g_drv_allow ? g_drv_hex : NULL) : install_fix(); break; case JOB_DRV_PREP: // "install anyway" accepts exactly this zip (its SHA-256), nothing else. (No comment after the call on the line of a break: it once swallowed the // break, and the install followed the prep at once, without the restart.) @@ -773,6 +793,22 @@ static void install(int job) else start_job(job, P_INSTALL); } +// The install of the fix (job: JOB_INSTALL_ALL / JOB_INSTALL_FIX). With the driver ticked its package is fetched and checked first (the driver pages), and the +// one elevated stage then does both: the UAC prompt comes once, before the restart. The driver-only first page (g_driver_only) has no install: it starts the prep itself. +static void go_install(int job) +{ + if (g_drv && !g_driver_only && g_drvmode == DRV_MODE_NONE && !g_pre) { g_pre = TRUE; g_inst_job = job; g_note[0] = 0; set_page(P_DRV_INTRO); } + else install(job); +} + +// "Skip" on the driver pages of the main flow: the fix is installed without the driver (the sign-in start is then registered by the install itself). +static void skip_driver(void) +{ + user_log(L"driver: skipped, the fix is installed without it"); + g_drv = FALSE; g_autostart_later = FALSE; g_pre = FALSE; + install(g_inst_job); +} + // Starts the acquire flow for the DynaRun setup or the driver (the same pages; a network check comes first inside the download). static void acq_start(const acq_desc *d) { @@ -945,6 +981,8 @@ static void drv_error(int rc) default: wsprintfW(g_note, T(L"The driver could not be prepared (code %d).", L"無法準備驅動程式(代碼 %d)。"), rc); break; } lstrcatW(g_note, T(L"\n\nYou can install the driver by hand instead: click \"Open the manual steps\".", L"\n\n也可以改用手動方式安裝,請按「開啟手動安裝說明」。")); + if (g_fix_done) lstrcatW(g_note, T(L"\n\nDynaRun's fix itself is installed. To try the driver again later, use \"Install Dyna Pro USB driver\" in the Start menu.", + L"\n\nDynaRun 的修正本身已經安裝好了。之後想再試一次驅動程式,可以用開始功能表裡的「安裝 Dyna Pro USB 驅動程式」。")); set_page(P_DRV_ERROR); } @@ -1170,11 +1208,19 @@ static void job_done(int job, int rc) break; case JOB_INSTALL_ALL: case JOB_INSTALL_FIX: + if (g_pre && (rc == 0 || rc >= DRV_E_HASH)) { // the fix is installed, and the driver step ran in the same elevated stage: its result (as for JOB_DRV_PREP) + cleanup_files(); + g_fix_done = TRUE; + if (rc == 0) drv_reboot_now(); + else if (rc == DRV_W_BDE) set_page(P_DRV_BDE); + else drv_error(rc); + break; + } if (rc == 0) { cleanup_files(); set_page(P_DONE); break; } if (rc == RC_RUNNING) { g_pending = job; set_page(P_RUNNING); break; } // DynaRun was started meanwhile if (rc == 2) { lstrcpyW(g_note, T(L"Nothing was installed: Windows needs your \"Yes\" to install.", L"沒有安裝:需要在 Windows 詢問時按「是」才能安裝。")); - set_page(job == JOB_INSTALL_ALL ? P_LICENSE : P_HELLO); + set_page(g_pre ? P_DRV_PRESS7 : job == JOB_INSTALL_ALL ? P_LICENSE : P_HELLO); // g_pre: the page with the button that started it break; } wsprintfW(g_note, T(L"The installation did not finish (code %d).\n\nRestart the computer and run this program again.", @@ -1215,7 +1261,7 @@ static void on_primary(void) if (g_driver_only) { g_drv = TRUE; g_autostart_later = FALSE; set_page(P_DRV_INTRO); break; } // the fix is current: straight to the driver g_drv = g_drv_avail && SendMessageW(H(ID_DRV), BM_GETCHECK, 0, 0) == BST_CHECKED; g_autostart_later = g_drv; // the driver restart comes first: the sign-in start is registered after it - if (g_installed) install(JOB_INSTALL_FIX); else { g_acq_fresh = FALSE; acq_start(&ACQ_SETUP); } + if (g_installed) go_install(JOB_INSTALL_FIX); else { g_acq_fresh = FALSE; acq_start(&ACQ_SETUP); } break; case P_FAIL: acq_start(g_acq); break; // Retry / Continue download case P_PASSWORD: @@ -1227,19 +1273,18 @@ static void on_primary(void) start_job(JOB_EXTRACT, P_EXTRACT); break; case P_CHECK: set_page(P_LICENSE); break; - case P_LICENSE: install(JOB_INSTALL_ALL); break; + case P_LICENSE: go_install(JOB_INSTALL_ALL); break; case P_RUNNING: g_close = TRUE; // the elevated stage closes DynaRun (see close_programs in setup.c) start_job(g_pending, P_INSTALL); break; case P_DONE: - if (g_drv) { set_page(P_DRV_INTRO); break; } // "Next": the driver start_dynarun(); DestroyWindow(g_hwnd); break; case P_ERROR: DestroyWindow(g_hwnd); break; case P_DRV_INTRO: acq_start(&ACQ_DRIVER); break; - case P_DRV_PRESS7: start_job(JOB_DRV_PREP, P_DRV_PREP); break; + case P_DRV_PRESS7: if (g_pre) install(g_inst_job); else start_job(JOB_DRV_PREP, P_DRV_PREP); break; // g_pre: the fix and the driver preparation in one elevated stage case P_DRV_HASH: hash_choice(FALSE); break; // "Cancel" is the default button case P_DRV_RETRY: g_drvzip[0] = 0; start_job(JOB_DRV_PREP, P_DRV_PREP); break; // the staged driver is still there case P_DRV_WARN: start_job(JOB_DRV_INSTALL, P_DRV_INSTALL); break; @@ -1274,12 +1319,12 @@ static void on_close(void) static void on_second(BOOL button) { if (g_page == P_DRV_HASH) hash_choice(button); // the button is "Install anyway"; Esc is a cancel - else if (g_page == P_FAIL && button && g_acq == &ACQ_DRIVER && can_skip_driver()) { g_drv = FALSE; set_page(P_DONE); } // "Skip": back to the end of the install + else if (g_page == P_FAIL && button && g_acq == &ACQ_DRIVER && can_skip_driver()) skip_driver(); // "Skip": the fix without the driver else if (g_page == P_FETCH && button) { if (g_paused) fetch_stopped(); // paused: no worker is running, finish at once else InterlockedExchange(&g_cancel, 1); // stop, then offer the other ways (also overrides a pause that is still taking effect) } - else if (g_page == P_DRV_INTRO && button && can_skip_driver()) { g_drv = FALSE; set_page(P_DONE); } // "Skip": back to the end of the install + else if (g_page == P_DRV_INTRO && button && can_skip_driver()) skip_driver(); // "Skip": the fix without the driver else if (g_page == P_DRV_RETRY || g_page == P_DRV_WARN || g_page == P_DRV_BDE) start_job(JOB_DRV_CANCEL, P_DRV_PREP); // the task, the menu flag and BitLocker back else if (g_page != P_INSTALL) on_close(); } diff --git a/tests/test_hardening.c b/tests/test_hardening.c index 1c8f380..992e14f 100644 --- a/tests/test_hardening.c +++ b/tests/test_hardening.c @@ -17,6 +17,7 @@ int update_run(const WCHAR *a) { (void)a; return 0; } int driver_verb(int argc, WCHAR **argv) { (void)argc; (void)argv; return DRV_NOVERB; } void driver_machine_stage(const WCHAR *p) { (void)p; } void driver_machine_uninstall(void) { } +int driver_prep_stage(const WCHAR *sid, const WCHAR *zip, const WCHAR *accept) { (void)sid; (void)zip; (void)accept; return 0; } static int g_fail, g_pass; #define CHECK(c, what) do { if (c) { g_pass++; } else { g_fail++; wprintf(L"FAIL line %d: %s\n", __LINE__, what); } } while (0)