Extract WindowsESD.pf separately

This commit is contained in:
paravis committed 2026-11-08 23:17:21 +03:00
1 parent a69409e526
commit 3c807fbcf2
6 files changed
+128 -45

No files matched your search

+6 -2
View File
@@ -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`, с
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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 ||
+23
View File
@@ -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;
+1
View File
@@ -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);