Extract WindowsESD.pf separately
This commit is contained in:
1 parent
a69409e526
commit
3c807fbcf2
6 files changed
+128
-45
No files matched your search
@@ -34,8 +34,12 @@ build\Release\ParavisInstaller.exe
|
|||||||
и защита системного диска Windows.
|
и защита системного диска Windows.
|
||||||
- Разметка через diskpart: FAT32 `PARAVIS` 16 ГБ, FAT `VTOYEFI` 32 МБ,
|
- Разметка через diskpart: FAT32 `PARAVIS` 16 ГБ, FAT `VTOYEFI` 32 МБ,
|
||||||
exFAT `DATA` (оставшийся объём).
|
exFAT `DATA` (оставшийся объём).
|
||||||
- Галочка «Не копировать Windows ESD» (по умолчанию снята): если включить,
|
- Если рядом с установщиком есть `WindowsESD.pf`, после `Data.pf` он
|
||||||
папка `WindowsESD` копируется, но файлы `*.esd` из неё удаляются с DATA.
|
распаковывается на раздел DATA (статус «Распаковка Windows ESD»).
|
||||||
|
- Галочка «Не копировать Windows ESD» (по умолчанию снята) пропускает
|
||||||
|
распаковку `WindowsESD.pf`. Если файла нет, галочка неактивна и
|
||||||
|
распаковка пропускается; если файл не является WIM — ошибка
|
||||||
|
«WindowsESD.pf повреждён».
|
||||||
- Отключённый диск переводится в онлайн перед разметкой.
|
- Отключённый диск переводится в онлайн перед разметкой.
|
||||||
- Проверка разметки по таблице разделов и меткам томов.
|
- Проверка разметки по таблице разделов и меткам томов.
|
||||||
- Распаковка DISM: образ 1 → `PARAVIS`, 2 → `VTOYEFI`, 3 → `DATA`, с
|
- Распаковка DISM: образ 1 → `PARAVIS`, 2 → `VTOYEFI`, 3 → `DATA`, с
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ public:
|
|||||||
std::wstring sig = L"-";
|
std::wstring sig = L"-";
|
||||||
std::wstring runStamp;
|
std::wstring runStamp;
|
||||||
std::wstring wimPath;
|
std::wstring wimPath;
|
||||||
|
std::wstring esdPfPath;
|
||||||
|
bool esdPfAvailable = false;
|
||||||
int testDisk = -1;
|
int testDisk = -1;
|
||||||
std::wstring workText;
|
std::wstring workText;
|
||||||
std::wstring labelText = L"Выбран накопитель:";
|
std::wstring labelText = L"Выбран накопитель:";
|
||||||
@@ -122,6 +124,7 @@ public:
|
|||||||
void CheckInstalled();
|
void CheckInstalled();
|
||||||
void Apply();
|
void Apply();
|
||||||
int ApplyImages(int disk, const std::wstring& wim);
|
int ApplyImages(int disk, const std::wstring& wim);
|
||||||
|
int ApplyWindowsEsd(int disk);
|
||||||
bool DismApply(const std::wstring& wim, int index, const std::wstring& dir,
|
bool DismApply(const std::wstring& wim, int index, const std::wstring& dir,
|
||||||
const std::wstring& caption);
|
const std::wstring& caption);
|
||||||
int RunCmd(const std::wstring& commandLine, const std::wstring& caption);
|
int RunCmd(const std::wstring& commandLine, const std::wstring& caption);
|
||||||
|
|||||||
+80
-36
@@ -6,7 +6,6 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -214,6 +213,12 @@ void App::Apply()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (esdPfAvailable && !IsWimFile(esdPfPath)) {
|
||||||
|
ShowMessage(MB_ICONERROR | MB_OK, L"WindowsESD.pf повреждён",
|
||||||
|
L"Файл WindowsESD.pf не является WIM-архивом:\r\n" + esdPfPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring message =
|
std::wstring message =
|
||||||
Format(L"Накопитель (%.1f ГБ)\r\n\r\n",
|
Format(L"Накопитель (%.1f ГБ)\r\n\r\n",
|
||||||
static_cast<double>(sizeBytes) / 1073741824.0);
|
static_cast<double>(sizeBytes) / 1073741824.0);
|
||||||
@@ -224,9 +229,14 @@ void App::Apply()
|
|||||||
static_cast<double>(p3) / 1024.0);
|
static_cast<double>(p3) / 1024.0);
|
||||||
message += L"Затем на разделы будут распакованы файлы из архива Data.pf\r\n";
|
message += L"Затем на разделы будут распакованы файлы из архива Data.pf\r\n";
|
||||||
message += L"(1 -> PARAVIS, 2 -> VTOYEFI, 3 -> DATA).\r\n\r\n";
|
message += L"(1 -> PARAVIS, 2 -> VTOYEFI, 3 -> DATA).\r\n\r\n";
|
||||||
|
if (esdPfAvailable) {
|
||||||
if (noEsd) {
|
if (noEsd) {
|
||||||
message += L"Файлы *.esd из папки WindowsESD копироваться не будут\r\n";
|
message += L"WindowsESD.pf распаковываться не будет.\r\n\r\n";
|
||||||
message += L"(остальные файлы папки будут скопированы).\r\n\r\n";
|
} else {
|
||||||
|
message += L"После Data.pf будет распакован WindowsESD.pf.\r\n\r\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message += L"WindowsESD.pf не найден - Windows ESD не будет распакован.\r\n\r\n";
|
||||||
}
|
}
|
||||||
message += L"ВНИМАНИЕ! ВСЕ ДАННЫЕ НА ЭТОМ ДИСКЕ БУДУТ УНИЧТОЖЕНЫ.\r\n";
|
message += L"ВНИМАНИЕ! ВСЕ ДАННЫЕ НА ЭТОМ ДИСКЕ БУДУТ УНИЧТОЖЕНЫ.\r\n";
|
||||||
message += L"Продолжить?";
|
message += L"Продолжить?";
|
||||||
@@ -341,6 +351,30 @@ void App::Apply()
|
|||||||
DebugLog(L"ApplyImages result=%d applied=%d cancel=%d", result, applied, cancel ? 1 : 0);
|
DebugLog(L"ApplyImages result=%d applied=%d cancel=%d", result, applied, cancel ? 1 : 0);
|
||||||
|
|
||||||
if (result == 1) {
|
if (result == 1) {
|
||||||
|
if (!noEsd && esdPfAvailable) {
|
||||||
|
int esdResult = ApplyWindowsEsd(disk);
|
||||||
|
if (esdResult == 3) {
|
||||||
|
SetWork(L"Отменено");
|
||||||
|
HideProgress();
|
||||||
|
BusySet(false);
|
||||||
|
HideProgress();
|
||||||
|
ShowMessage(MB_ICONINFORMATION | MB_OK, L"Отменено",
|
||||||
|
L"Операция отменена пользователем.\r\n\r\n"
|
||||||
|
L"Диск размечен, Windows ESD не распакован.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (esdResult == 2) {
|
||||||
|
SetWork(L"Ошибка Windows ESD");
|
||||||
|
HideProgress();
|
||||||
|
ShowMessage(MB_ICONERROR | MB_OK, L"Ошибка Windows ESD",
|
||||||
|
L"Не удалось распаковать WindowsESD.pf.\r\n\r\n"
|
||||||
|
L"Проверьте, что файл не повреждён.");
|
||||||
|
BusySet(false);
|
||||||
|
HideProgress();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring first = GetPartitionLetter(disk, 0);
|
std::wstring first = GetPartitionLetter(disk, 0);
|
||||||
DebugLog(L"partition0=%s", first.c_str());
|
DebugLog(L"partition0=%s", first.c_str());
|
||||||
|
|
||||||
@@ -456,39 +490,6 @@ int App::ApplyImages(int disk, const std::wstring& wim)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 2 && noEsd) {
|
|
||||||
std::wstring esdDir = dir + L"WindowsESD";
|
|
||||||
std::error_code ec;
|
|
||||||
if (std::filesystem::exists(esdDir, ec)) {
|
|
||||||
std::filesystem::recursive_directory_iterator it(
|
|
||||||
esdDir, std::filesystem::directory_options::skip_permission_denied, ec);
|
|
||||||
const std::filesystem::recursive_directory_iterator end;
|
|
||||||
while (it != end) {
|
|
||||||
if (ec) {
|
|
||||||
DebugLog(L"skip ESD: scan stopped ec=%d", ec.value());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const std::filesystem::directory_entry& entry = *it;
|
|
||||||
std::error_code fileEc;
|
|
||||||
if (entry.is_regular_file(fileEc)) {
|
|
||||||
std::wstring ext = entry.path().extension().wstring();
|
|
||||||
std::transform(ext.begin(), ext.end(), ext.begin(),
|
|
||||||
[](wchar_t c) {
|
|
||||||
return static_cast<wchar_t>(towlower(c));
|
|
||||||
});
|
|
||||||
if (ext == L".esd") {
|
|
||||||
std::error_code removeEc;
|
|
||||||
std::filesystem::remove(entry.path(), removeEc);
|
|
||||||
DebugLog(L"skip ESD: %s removed=%d ec=%d",
|
|
||||||
entry.path().c_str(),
|
|
||||||
removeEc ? 0 : 1, removeEc.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it.increment(ec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++applied;
|
++applied;
|
||||||
|
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
@@ -499,6 +500,49 @@ int App::ApplyImages(int disk, const std::wstring& wim)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int App::ApplyWindowsEsd(int disk)
|
||||||
|
{
|
||||||
|
std::wstring dir;
|
||||||
|
for (int attempt = 0; attempt < 15; ++attempt) {
|
||||||
|
dir = GetPartitionLetter(disk, 2);
|
||||||
|
if (!dir.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SleepPump(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir.empty()) {
|
||||||
|
ShowMessage(MB_ICONERROR | MB_OK, L"Ошибка",
|
||||||
|
L"Не удалось определить букву раздела DATA.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (cancel) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsWimFile(esdPfPath)) {
|
||||||
|
ShowMessage(MB_ICONERROR | MB_OK, L"WindowsESD.pf повреждён",
|
||||||
|
L"Файл WindowsESD.pf не является WIM-архивом:\r\n" + esdPfPath);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring caption = L"Распаковка Windows ESD";
|
||||||
|
DebugLog(L"ApplyWindowsEsd %s -> %s", esdPfPath.c_str(), dir.c_str());
|
||||||
|
phase = 2;
|
||||||
|
ShowProgress(0);
|
||||||
|
SetWork(caption);
|
||||||
|
|
||||||
|
bool ok = DismApply(esdPfPath, 1, dir, caption);
|
||||||
|
phase = 0;
|
||||||
|
if (!ok) {
|
||||||
|
if (cancel) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool App::DismApply(const std::wstring& wim, int index, const std::wstring& dir,
|
bool App::DismApply(const std::wstring& wim, int index, const std::wstring& dir,
|
||||||
const std::wstring& caption)
|
const std::wstring& caption)
|
||||||
{
|
{
|
||||||
|
|||||||
+15
-7
@@ -187,6 +187,10 @@ bool App::Init(HWND window)
|
|||||||
}
|
}
|
||||||
CreateFonts();
|
CreateFonts();
|
||||||
|
|
||||||
|
esdPfPath = JoinPath(GetExeDir(), L"WindowsESD.pf");
|
||||||
|
esdPfAvailable = FileExists(esdPfPath);
|
||||||
|
DebugLog(L"WindowsESD.pf: %s available=%d", esdPfPath.c_str(), esdPfAvailable ? 1 : 0);
|
||||||
|
|
||||||
hProgress = CreateWindowExW(0, PROGRESS_CLASSW, nullptr,
|
hProgress = CreateWindowExW(0, PROGRESS_CLASSW, nullptr,
|
||||||
WS_CHILD | PBS_SMOOTH,
|
WS_CHILD | PBS_SMOOTH,
|
||||||
14, 152, 348, 5,
|
14, 152, 348, 5,
|
||||||
@@ -500,13 +504,17 @@ void App::Paint(HDC dc)
|
|||||||
const int cbX = 16;
|
const int cbX = 16;
|
||||||
const int cbY = 114;
|
const int cbY = 114;
|
||||||
const int cbSize = 14;
|
const int cbSize = 14;
|
||||||
FillRectColor(memory, cbX, cbY, cbSize, cbSize, RGB(255, 255, 255));
|
bool checkEnabled = esdPfAvailable && !busy;
|
||||||
|
COLORREF boxFill = checkEnabled ? RGB(255, 255, 255) : ColorFromHex(0xF2F3F5);
|
||||||
|
COLORREF boxBorder = checkEnabled ? checkBorder : ColorFromHex(0xD5DAE3);
|
||||||
|
COLORREF boxText = checkEnabled ? checkFg : ColorFromHex(0xA0A6B1);
|
||||||
|
FillRectColor(memory, cbX, cbY, cbSize, cbSize, boxFill);
|
||||||
RECT cbRect{ cbX, cbY, cbX + cbSize - 1, cbY + cbSize - 1 };
|
RECT cbRect{ cbX, cbY, cbX + cbSize - 1, cbY + cbSize - 1 };
|
||||||
HBRUSH cbBrush = CreateSolidBrush(checkBorder);
|
HBRUSH cbBrush = CreateSolidBrush(boxBorder);
|
||||||
FrameRect(memory, &cbRect, cbBrush);
|
FrameRect(memory, &cbRect, cbBrush);
|
||||||
DeleteObject(cbBrush);
|
DeleteObject(cbBrush);
|
||||||
if (noEsd) {
|
if (noEsd && esdPfAvailable) {
|
||||||
COLORREF markColor = dimmed ? ColorFromHex(0xA0A6B1) : ColorFromHex(0x2563EB);
|
COLORREF markColor = checkEnabled ? ColorFromHex(0x2563EB) : ColorFromHex(0xA0A6B1);
|
||||||
HPEN pen = CreatePen(PS_SOLID, 2, markColor);
|
HPEN pen = CreatePen(PS_SOLID, 2, markColor);
|
||||||
HGDIOBJ oldPen = SelectObject(memory, pen);
|
HGDIOBJ oldPen = SelectObject(memory, pen);
|
||||||
MoveToEx(memory, cbX + 3, cbY + 7, nullptr);
|
MoveToEx(memory, cbX + 3, cbY + 7, nullptr);
|
||||||
@@ -516,7 +524,7 @@ void App::Paint(HDC dc)
|
|||||||
DeleteObject(pen);
|
DeleteObject(pen);
|
||||||
}
|
}
|
||||||
DrawTextRect(memory, L"Не копировать Windows ESD", fontText, 36, 112, 300, 18,
|
DrawTextRect(memory, L"Не копировать Windows ESD", fontText, 36, 112, 300, 18,
|
||||||
checkFg, DT_LEFT | DT_VCENTER);
|
boxText, DT_LEFT | DT_VCENTER);
|
||||||
|
|
||||||
if (busy) {
|
if (busy) {
|
||||||
DrawTextRect(memory, workText, fontBold, 14, 132, 348, 18,
|
DrawTextRect(memory, workText, fontBold, 14, 132, 348, 18,
|
||||||
@@ -725,7 +733,7 @@ void App::OnPoll()
|
|||||||
checkDown = true;
|
checkDown = true;
|
||||||
} else if (checkDown) {
|
} else if (checkDown) {
|
||||||
checkDown = false;
|
checkDown = false;
|
||||||
if (hit == Hit::Check && !leftDown) {
|
if (hit == Hit::Check && !leftDown && esdPfAvailable) {
|
||||||
noEsd = !noEsd;
|
noEsd = !noEsd;
|
||||||
DebugLog(L"checkbox noEsd=%d", noEsd ? 1 : 0);
|
DebugLog(L"checkbox noEsd=%d", noEsd ? 1 : 0);
|
||||||
InvalidateAll();
|
InvalidateAll();
|
||||||
@@ -799,7 +807,7 @@ void App::OnPoll()
|
|||||||
(hit == Hit::Combo || hit == Hit::Drop || hit == Hit::DropName ||
|
(hit == Hit::Combo || hit == Hit::Drop || hit == Hit::DropName ||
|
||||||
hit == Hit::DropSize || hit == Hit::Arrow);
|
hit == Hit::DropSize || hit == Hit::Arrow);
|
||||||
comboFrame = comboHover ? ColorFromHex(0x7FA6F0) : ColorFromHex(0xD5DAE3);
|
comboFrame = comboHover ? ColorFromHex(0x7FA6F0) : ColorFromHex(0xD5DAE3);
|
||||||
checkBorder = (hit == Hit::Check) ? ColorFromHex(0x7FA6F0) : ColorFromHex(0x9AA3B2);
|
checkBorder = (esdPfAvailable && hit == Hit::Check) ? ColorFromHex(0x7FA6F0) : ColorFromHex(0x9AA3B2);
|
||||||
|
|
||||||
if (!disks.empty() &&
|
if (!disks.empty() &&
|
||||||
(hit == Hit::Drop || hit == Hit::Arrow || hit == Hit::DropName ||
|
(hit == Hit::Drop || hit == Hit::Arrow || hit == Hit::DropName ||
|
||||||
|
|||||||
@@ -82,6 +82,29 @@ bool FileExists(const std::wstring& path)
|
|||||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsWimFile(const std::wstring& path)
|
||||||
|
{
|
||||||
|
HANDLE file = CreateFileW(path.c_str(), GENERIC_READ,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
OPEN_EXISTING, 0, nullptr);
|
||||||
|
if (file == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char signature[8] = {};
|
||||||
|
DWORD read = 0;
|
||||||
|
BOOL ok = ReadFile(file, signature, sizeof(signature), &read, nullptr);
|
||||||
|
CloseHandle(file);
|
||||||
|
if (!ok || read != sizeof(signature)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature[0] == 'M' && signature[1] == 'S' &&
|
||||||
|
signature[2] == 'W' && signature[3] == 'I' &&
|
||||||
|
signature[4] == 'M' && signature[5] == 0 &&
|
||||||
|
signature[6] == 0 && signature[7] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsAdmin()
|
bool IsAdmin()
|
||||||
{
|
{
|
||||||
HANDLE token = nullptr;
|
HANDLE token = nullptr;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ std::wstring GetExeDir();
|
|||||||
std::wstring GetRunStamp();
|
std::wstring GetRunStamp();
|
||||||
std::wstring JoinPath(const std::wstring& dir, const std::wstring& name);
|
std::wstring JoinPath(const std::wstring& dir, const std::wstring& name);
|
||||||
bool FileExists(const std::wstring& path);
|
bool FileExists(const std::wstring& path);
|
||||||
|
bool IsWimFile(const std::wstring& path);
|
||||||
bool IsAdmin();
|
bool IsAdmin();
|
||||||
std::string WideToAnsi(const std::wstring& text, UINT codepage = CP_ACP);
|
std::string WideToAnsi(const std::wstring& text, UINT codepage = CP_ACP);
|
||||||
std::wstring AnsiToWide(const std::string& text, UINT codepage = CP_ACP);
|
std::wstring AnsiToWide(const std::string& text, UINT codepage = CP_ACP);
|
||||||
|
|||||||
Reference in new issue
Block a user