#include #include #include #include #include #NoTrayIcon #RequireAdmin #pragma compile(Stripper, True) #pragma compile(ProductVersion, 3.2.0) #pragma compile(ProductName, "Change bootLoader") #pragma compile(FileDescription, CBL) #pragma compile(LegalCopyright, paravis.ru@2024) #pragma compile(CompanyName, paravis.ru@2024) Opt("ExpandEnvStrings", 1) Opt("GUIOnEventMode", 0) Opt("MustDeclareVars", 1) ; --- оформление (как у установщика) Global Const $CLR_BG = 0xF1F4F9 Global Const $CLR_HEAD = 0x1E2A44 Global Const $CLR_DIM = 0x6B7280 Global Const $CLR_BORDER = 0xBFC9D6 Global Const $CLR_BTN = 0xFFFFFF Global Const $CLR_HOVER = 0xE4EEFF Global Const $CLR_PRESS = 0xCFE0FF Global Const $CLR_TEXT = 0x14202E Global $sDisk = StringLeft(@ScriptDir, 2) Global $boot = ($sDisk & "\efi\Paravis\Boot") Global $bootice = ($boot & "\bootice.exe") ; защита: не даём случайно записать MBR в диск, где нет сборки Paravis If Not FileExists($bootice) Or Not FileExists($boot & "\NOT.DEL") Then MsgBox(BitOR($MB_ICONERROR, $MB_OK), "Change BootLoader", "Этот диск не является сборкой Paravis (нет bootice.exe или NOT.DEL):" & @CRLF & $sDisk) Exit EndIf Global $hMain, $hMin, $hClose, $hTitle, $hSub Global $aFrame[7], $aBtn[7], $aBg[7], $aName[7] Global $gDown = -1, $gBusy = False, $gDrag = False, $gDragX = 0, $gDragY = 0 Global $gMinBg = -1, $gCloseBg = -1 ; --- окно $hMain = GUICreate("Change BootLoader", 376, 208, -1, -1, $WS_POPUP, $WS_EX_APPWINDOW) GUISetBkColor($CLR_BG, $hMain) GUISetFont(9, 400, 0, "Tahoma", $hMain) ; шапка Global $hHead = GUICtrlCreateLabel("", 0, 0, 376, 48) GUICtrlSetBkColor($hHead, $CLR_HEAD) $hTitle = GUICtrlCreateLabel("Paravis Flash", 16, 2, 300, 24) GUICtrlSetFont($hTitle, 15, 700, 0, "Tahoma") GUICtrlSetColor($hTitle, 0xFFFFFF) GUICtrlSetBkColor($hTitle, $CLR_HEAD) $hSub = GUICtrlCreateLabel("Смена загрузчика", 18, 27, 300, 14) GUICtrlSetColor($hSub, 0xC7D0E0) GUICtrlSetBkColor($hSub, $CLR_HEAD) $hMin = GUICtrlCreateLabel("—", 306, 2, 30, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE, $SS_NOTIFY)) GUICtrlSetFont($hMin, 10, 400, 0, "Tahoma") GUICtrlSetColor($hMin, 0xC7D0E0) GUICtrlSetBkColor($hMin, $CLR_HEAD) $hClose = GUICtrlCreateLabel("✕", 338, 2, 30, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE, $SS_NOTIFY)) GUICtrlSetFont($hClose, 9, 400, 0, "Tahoma") GUICtrlSetColor($hClose, 0xC7D0E0) GUICtrlSetBkColor($hClose, $CLR_HEAD) ; --- подписи секций Local $hSecL = GUICtrlCreateLabel("LEGACY BIOS", 15, 56, 200, 14) GUICtrlSetFont($hSecL, 8, 700, 0, "Tahoma") GUICtrlSetColor($hSecL, $CLR_DIM) GUICtrlSetBkColor($hSecL, $CLR_BG) Local $hSecU = GUICtrlCreateLabel("UEFI", 15, 152, 200, 14) GUICtrlSetFont($hSecU, 8, 700, 0, "Tahoma") GUICtrlSetColor($hSecU, $CLR_DIM) GUICtrlSetBkColor($hSecU, $CLR_BG) ; --- кнопки: рамка 1 px + надпись $aName[0] = "XorBoot" $aName[1] = "Bootmgr" $aName[2] = "Grub4Dos" $aName[3] = "Grub2" $aName[4] = "Bootmgr" $aName[5] = "Grub2" $aName[6] = "Xorboot" Local $aPos[7][4] = [ _ [14, 72, 170, 32], _ [192, 72, 170, 32], _ [14, 110, 170, 32], _ [192, 110, 170, 32], _ [14, 168, 110, 32], _ [132, 168, 110, 32], _ [250, 168, 110, 32] ] Local $i For $i = 0 To 6 $aFrame[$i] = GUICtrlCreateLabel("", $aPos[$i][0] - 1, $aPos[$i][1] - 1, $aPos[$i][2] + 2, $aPos[$i][3] + 2) GUICtrlSetBkColor($aFrame[$i], $CLR_BORDER) $aBtn[$i] = GUICtrlCreateLabel($aName[$i], $aPos[$i][0], $aPos[$i][1], $aPos[$i][2], $aPos[$i][3], BitOR($SS_CENTER, $SS_CENTERIMAGE, $SS_NOTIFY)) GUICtrlSetFont($aBtn[$i], 10, 400, 0, "Segoe UI Semibold") GUICtrlSetColor($aBtn[$i], $CLR_TEXT) GUICtrlSetBkColor($aBtn[$i], $CLR_BTN) $aBg[$i] = $CLR_BTN Next GUISetState(@SW_SHOW, $hMain) AdlibRegister("_Poll", 40) While 1 If GUIGetMsg() = $GUI_EVENT_CLOSE Then Exit Sleep(30) WEnd ; ================= действия ================= Func _Run($idx) If $gBusy Then Return ; перед любым действием подтверждаем целевой диск If Not FileExists($boot & "\NOT.DEL") Or _DiskNumber($sDisk) < 0 Then _Msg("Целевой диск не подтверждён:" & @CRLF & $sDisk & @CRLF & _ "нет \efi\Paravis\Boot\NOT.DEL или не найден PhysicalDrive.") Return EndIf $gBusy = True Switch $idx Case 0 _LegacyXor() Case 1 _LegacyMgr() Case 2 _LegacyG4d() Case 3 _LegacyGrub2() Case 4 _UefiMgr() Case 5 _UefiGrub2() Case 6 _UefiXor() EndSwitch $gBusy = False EndFunc Func _LegacyXor() FileDelete($sDisk & "\bootmgr") FileDelete($sDisk & "\grldr") RunWait($bootice & " /DEVICE=" & $sDisk & " /mbr /restore /file=" & $boot & "\xor\xmbr.bin /keep_dpt /quiet") RunWait($bootice & " /DEVICE=" & $sDisk & " /pbr /restore /file=" & $boot & "\xor\xpbr.bin /keep_bpb /quiet") _Done("XorBoot") EndFunc Func _LegacyMgr() FileDelete($sDisk & "\bootmgr") FileDelete($sDisk & "\grldr") FileCopy($boot & "\mgr\bootmgr", $sDisk & "\bootmgr") RunWait($bootice & " /DEVICE=" & $sDisk & " /mbr /install /type=nt60 /quiet") RunWait($bootice & " /DEVICE=" & $sDisk & " /pbr /install /type=bootmgr /quiet") _Done("Bootmgr") EndFunc Func _LegacyG4d() FileDelete($sDisk & "\bootmgr") FileDelete($sDisk & "\grldr") FileCopy($boot & "\g4d\grldr", $sDisk & "\grldr") RunWait($bootice & " /DEVICE=" & $sDisk & " /mbr /install /type=GRUB4DOS /quiet") RunWait($bootice & " /DEVICE=" & $sDisk & " /pbr /install /type=GRUB4DOS /quiet") _Done("Grub4Dos") EndFunc Func _LegacyGrub2() Local $src = $boot & "\loaders\grub2-bios" Local $dst = $boot & "\grub2\bios" If Not FileExists($src & "\boot.img") Or Not FileExists($src & "\core.img") Then _Msg("Файлы GRUB2 для Legacy BIOS не найдены:" & @CRLF & $src) Return EndIf If Not FileExists($dst & "\grub.cfg") Then _Msg("Не найден основной grub.cfg:" & @CRLF & $dst & "\grub.cfg") Return EndIf Local $disk = _DiskNumber($sDisk) If $disk < 0 Then _Msg("Не удалось определить номер физического диска для " & $sDisk) Return EndIf ; убрать файлы других Legacy-загрузчиков из корня FileDelete($sDisk & "\bootmgr") FileDelete($sDisk & "\grldr") ; дерево для core.img: модули и меню должны лежать по префиксу /efi/Paravis/Boot/grub2/bios DirCreate($dst) DirCreate($dst & "\i386-pc") FileCopy($src & "\boot.img", $dst & "\boot.img", 9) FileCopy($src & "\core.img", $dst & "\core.img", 9) FileCopy($src & "\make-paravis-mbr.ps1", $dst & "\make-paravis-mbr.ps1", 9) ; grub.cfg НЕ копируем: в loaders лежит тестовое меню, рабочее уже в $dst RunWait(@ComSpec & ' /c xcopy /E /I /Y /Q "' & $src & '\i386-pc" "' & $dst & '\i386-pc" > nul 2>&1', "", @SW_HIDE) ; MBR-образ: наш boot.img (0..439) + текущая таблица разделов (440..511) Local $rc1 = RunWait('powershell.exe -NoProfile -ExecutionPolicy Bypass -File "' & $dst & '\make-paravis-mbr.ps1" -Disk ' & $disk & ' -Boot "' & $dst & '\boot.img" -Out "' & $dst & '\paravis-mbr-table.img"', "", @SW_HIDE) If $rc1 <> 0 Then _Msg("Не удалось сформировать MBR-образ (код " & $rc1 & ").") Return EndIf ; Bootice /sectors: MBR (сектор 0) и core.img (с сектора 1); таблица разделов сохраняется Local $rc2 = RunWait('"' & $bootice & '" /DEVICE=' & $sDisk & ' /sectors /restore /file="' & $dst & '\paravis-mbr-table.img" /lba=0 /sectors=1 /quiet', "", @SW_HIDE) If $rc2 <> 0 Then _Msg("Ошибка записи MBR (код " & $rc2 & ").") Return EndIf Local $rc3 = RunWait('"' & $bootice & '" /DEVICE=' & $sDisk & ' /sectors /restore /file="' & $dst & '\core.img" /lba=1 /sectors=591 /quiet', "", @SW_HIDE) If $rc3 <> 0 Then _Msg("Ошибка записи core.img (код " & $rc3 & ").") Return EndIf _Done("Grub2 (Legacy)") EndFunc Func _UefiMgr() _UefiClean() FileCopy($boot & "\mgr\UEFI\bootx64.efi", $sDisk & "\efi\boot\bootx64.efi") FileCopy($boot & "\mgr\UEFI\bootia32.efi", $sDisk & "\efi\boot\bootia32.efi") _Done("UEFI Bootmgr") EndFunc Func _UefiGrub2() ; bootia32 не трогаем: на ia32 остаётся XorBoot FileDelete($sDisk & "\efi\boot\bootx64.efi") FileDelete($sDisk & "\efi\boot\fbx64.efi") FileDelete($sDisk & "\efi\boot\mmx64.efi") FileCopy($boot & "\loaders\grub2\bootx64.efi", $sDisk & "\efi\boot\bootx64.efi") FileCopy($boot & "\loaders\grub2\fbx64.efi", $sDisk & "\efi\boot\fbx64.efi") FileCopy($boot & "\loaders\grub2\mmx64.efi", $sDisk & "\efi\boot\mmx64.efi") _Done("UEFI GRUB2") EndFunc Func _UefiXor() _UefiClean() FileCopy($boot & "\xor\UEFI\bootx64.efi", $sDisk & "\efi\boot\bootx64.efi") FileCopy($boot & "\xor\UEFI\bootia32.efi", $sDisk & "\efi\boot\bootia32.efi") _Done("UEFI Xorboot") EndFunc Func _UefiClean() FileDelete($sDisk & "\efi\boot\bootx64.efi") FileDelete($sDisk & "\efi\boot\bootia32.efi") FileDelete($sDisk & "\efi\boot\fbx64.efi") FileDelete($sDisk & "\efi\boot\mmx64.efi") EndFunc ; ================= служба ================= Func _Done($name) _Msg("Загрузчик изменён: " & $name) EndFunc Func _Msg($text) Local $prev = $gBusy $gBusy = True MsgBox(BitOR($MB_ICONINFORMATION, $MB_OK), "Change BootLoader", $text) $gBusy = $prev EndFunc Func _DiskNumber($letter) Local $oWMI = ObjGet("winmgmts:\\.\root\cimv2") If Not IsObj($oWMI) Then Return -1 Local $col = $oWMI.ExecQuery("SELECT * FROM Win32_DiskDrive") If Not IsObj($col) Then Return -1 For $d In $col Local $parts = $oWMI.ExecQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" & $d.DeviceID & "'} WHERE AssocClass=Win32_DiskDriveToDiskPartition") If IsObj($parts) Then For $p In $parts Local $lds = $oWMI.ExecQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" & $p.DeviceID & "'} WHERE AssocClass=Win32_LogicalDiskToPartition") If IsObj($lds) Then For $l In $lds If StringUpper(String($l.DeviceID)) = StringUpper($letter) Then Return Number(StringRegExpReplace($d.DeviceID, ".*PHYSICALDRIVE(\d+).*", "$1")) EndIf Next EndIf Next EndIf Next Return -1 EndFunc Func _Poll() Local $ci = GUIGetCursorInfo($hMain) If Not IsArray($ci) Then Return ; кнопки шапки Local $minBg = $CLR_HEAD, $closeBg = $CLR_HEAD If $ci[4] = $hMin Then If $ci[2] = 1 Then $minBg = 0x3A4A6B Else $minBg = 0x2C3A57 EndIf EndIf If $ci[4] = $hClose Then If $ci[2] = 1 Then $closeBg = 0xC0392B Else $closeBg = 0xE04B3F EndIf EndIf If $minBg <> $gMinBg Then GUICtrlSetBkColor($hMin, $minBg) $gMinBg = $minBg EndIf If $closeBg <> $gCloseBg Then GUICtrlSetBkColor($hClose, $closeBg) $gCloseBg = $closeBg EndIf ; нажатия в шапке Static $minDown = False, $closeDown = False If $ci[4] = $hMin And $ci[2] = 1 Then $minDown = True ElseIf $minDown Then $minDown = False If $ci[4] = $hMin And $ci[2] = 0 Then GUISetState(@SW_MINIMIZE, $hMain) EndIf If $ci[4] = $hClose And $ci[2] = 1 Then $closeDown = True ElseIf $closeDown Then $closeDown = False If $ci[4] = $hClose And $ci[2] = 0 Then Exit EndIf ; перетаскивание за шапку If ($ci[4] = $hHead Or $ci[4] = $hTitle Or $ci[4] = $hSub) And $ci[2] = 1 And Not $gDrag Then Local $m = MouseGetPos() Local $w = WinGetPos($hMain) If IsArray($m) And IsArray($w) Then $gDrag = True $gDragX = $m[0] - $w[0] $gDragY = $m[1] - $w[1] EndIf EndIf If $gDrag Then If $ci[2] = 0 Then $gDrag = False Else Local $m2 = MouseGetPos() If IsArray($m2) Then WinMove($hMain, "", $m2[0] - $gDragX, $m2[1] - $gDragY) EndIf EndIf ; подсветка кнопок Local $i For $i = 0 To 6 Local $bg = $CLR_BTN If $ci[4] = $aBtn[$i] Or $ci[4] = $aFrame[$i] Then If $ci[2] = 1 Then $bg = $CLR_PRESS Else $bg = $CLR_HOVER EndIf EndIf If $aBg[$i] <> $bg Then GUICtrlSetBkColor($aBtn[$i], $bg) $aBg[$i] = $bg EndIf Next ; клик по кнопке If $gBusy Then Return If $ci[2] = 1 Then For $i = 0 To 6 If $ci[4] = $aBtn[$i] Or $ci[4] = $aFrame[$i] Then $gDown = $i Return EndIf Next $gDown = -1 ElseIf $gDown >= 0 Then Local $idx = $gDown $gDown = -1 If $ci[4] = $aBtn[$idx] Or $ci[4] = $aFrame[$idx] Then _Run($idx) EndIf EndFunc