]> glassweightruler.freedombox.rocks Git - Ventoy.git/blobdiff - vtoyjump/vtoyjump/vtoyjump.c
Update readme
[Ventoy.git] / vtoyjump / vtoyjump / vtoyjump.c
index 1936143a1f865a7e6a268ab066df4390830b5be0..f6a2edbf544870ff007b0b2b976604e2c4023d70 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************\r
 * vtoyjump.c\r
 *\r
-* Copyright (c) 2020, longpanda <admin@ventoy.net>\r
+* Copyright (c) 2021, longpanda <admin@ventoy.net>\r
 *\r
 * This program is free software; you can redistribute it and/or\r
 * modify it under the terms of the GNU General Public License as\r
 static ventoy_os_param g_os_param;\r
 static ventoy_windows_data g_windows_data;\r
 static UINT8 g_os_param_reserved[32];\r
-static BOOL g_64bit_system = FALSE;\r
+static INT g_system_bit = VTOY_BIT;\r
 static ventoy_guid g_ventoy_guid = VENTOY_GUID;\r
 static HANDLE g_vtoylog_mutex = NULL;\r
 static HANDLE g_vtoyins_mutex = NULL;\r
 \r
-#define VTOY_PID_FILE "X:\\Windows\\System32\\pidventoy"\r
+static BOOL g_wimboot_mode = FALSE;\r
+\r
+static DWORD g_vtoy_disk_drive;\r
+\r
+static CHAR g_prog_full_path[MAX_PATH];\r
+static CHAR g_prog_dir[MAX_PATH];\r
+static CHAR g_prog_name[MAX_PATH];\r
+\r
+#define VTOY_PECMD_PATH      "X:\\Windows\\system32\\ventoy\\PECMD.EXE"\r
+#define ORG_PECMD_PATH       "X:\\Windows\\system32\\PECMD.EXE"\r
+#define ORG_PECMD_BK_PATH    "X:\\Windows\\system32\\VTOYJUMP.EXE"\r
+\r
+#define WIMBOOT_FILE         "X:\\Windows\\system32\\vtoy_wimboot"\r
+#define WIMBOOT_DONE         "X:\\Windows\\system32\\vtoy_wimboot_done"\r
+\r
+#define AUTO_RUN_BAT    "X:\\VentoyAutoRun.bat"\r
+#define AUTO_RUN_LOG    "X:\\VentoyAutoRun.log"\r
+\r
+#define VTOY_AUTO_FILE   "X:\\_vtoy_auto_install"\r
+\r
+#define LOG_FILE  "X:\\Windows\\system32\\ventoy.log"\r
 #define MUTEX_LOCK(hmutex)  if (hmutex != NULL) LockStatus = WaitForSingleObject(hmutex, INFINITE)\r
 #define MUTEX_UNLOCK(hmutex)  if (hmutex != NULL && WAIT_OBJECT_0 == LockStatus) ReleaseMutex(hmutex)\r
 \r
+static const char * GetFileNameInPath(const char *fullpath)\r
+{\r
+    int i;\r
+\r
+    if (strstr(fullpath, ":"))\r
+    {\r
+        for (i = (int)strlen(fullpath); i > 0; i--)\r
+        {\r
+            if (fullpath[i - 1] == '/' || fullpath[i - 1] == '\\')\r
+            {\r
+                return fullpath + i;\r
+            }\r
+        }\r
+    }\r
+\r
+    return fullpath;\r
+}\r
+\r
+static int split_path_name(char *fullpath, char *dir, char *name)\r
+{\r
+    CHAR ch;\r
+    CHAR *Pos = NULL;\r
+\r
+    Pos = (CHAR *)GetFileNameInPath(fullpath);\r
+\r
+    strcpy_s(name, MAX_PATH, Pos);\r
+\r
+    ch = *(Pos - 1);\r
+    *(Pos - 1) = 0;\r
+    strcpy_s(dir, MAX_PATH, fullpath);\r
+    *(Pos - 1) = ch;\r
+\r
+    return 0;\r
+}\r
+\r
+static void TrimString(CHAR *String, BOOL TrimLeft)\r
+{\r
+    CHAR *Pos1 = String;\r
+    CHAR *Pos2 = String;\r
+    size_t Len = strlen(String);\r
+\r
+    while (Len > 0)\r
+    {\r
+        if (String[Len - 1] != ' ' && String[Len - 1] != '\t')\r
+        {\r
+            break;\r
+        }\r
+        String[Len - 1] = 0;\r
+        Len--;\r
+    }\r
+\r
+    if (TrimLeft)\r
+    {        \r
+        while (*Pos1 == ' ' || *Pos1 == '\t')\r
+        {\r
+            Pos1++;\r
+        }\r
+\r
+        while (*Pos1)\r
+        {\r
+            *Pos2++ = *Pos1++;\r
+        }\r
+        *Pos2++ = 0;\r
+    }\r
+\r
+    return;\r
+}\r
+\r
+static int VentoyProcessRunCmd(const char *Fmt, ...)\r
+{\r
+    int Len = 0;\r
+    va_list Arg;\r
+    STARTUPINFOA Si;\r
+    PROCESS_INFORMATION Pi;\r
+    char szBuf[1024] = { 0 };\r
+\r
+    va_start(Arg, Fmt);\r
+    Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);\r
+    va_end(Arg);\r
+\r
+    GetStartupInfoA(&Si);\r
+    Si.dwFlags |= STARTF_USESHOWWINDOW;\r
+    Si.wShowWindow = SW_HIDE;\r
+\r
+    Log("Process Run: <%s>", szBuf);\r
+    CreateProcessA(NULL, szBuf, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+    WaitForSingleObject(Pi.hProcess, INFINITE);\r
+\r
+    return 0;\r
+}\r
+\r
+static CHAR VentoyGetFirstFreeDriveLetter(BOOL Reverse)\r
+{\r
+    int i;\r
+    CHAR Letter = 'T';\r
+    DWORD Drives;\r
+\r
+    Drives = GetLogicalDrives();\r
+\r
+    if (Reverse)\r
+    {\r
+        for (i = 25; i >= 2; i--)\r
+        {\r
+            if (0 == (Drives & (1 << i)))\r
+            {\r
+                Letter = 'A' + i;\r
+                break;\r
+            }\r
+        }\r
+    }\r
+    else\r
+    {\r
+        for (i = 2; i < 26; i++)\r
+        {\r
+            if (0 == (Drives & (1 << i)))\r
+            {\r
+                Letter = 'A' + i;\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    Log("FirstFreeDriveLetter %u %C:", Reverse, Letter);\r
+    return Letter;\r
+}\r
+\r
 void Log(const char *Fmt, ...)\r
 {\r
-       va_list Arg;\r
-       int Len = 0;\r
-       FILE *File = NULL;\r
-       SYSTEMTIME Sys;\r
-       char szBuf[1024];\r
+    va_list Arg;\r
+    int Len = 0;\r
+    FILE *File = NULL;\r
+    SYSTEMTIME Sys;\r
+    char szBuf[1024];\r
     DWORD LockStatus = 0;\r
     DWORD PID = GetCurrentProcessId();\r
 \r
-       GetLocalTime(&Sys);\r
-       Len += sprintf_s(szBuf, sizeof(szBuf),\r
-               "[%4d/%02d/%02d %02d:%02d:%02d.%03d] [%u] ",\r
-               Sys.wYear, Sys.wMonth, Sys.wDay,\r
-               Sys.wHour, Sys.wMinute, Sys.wSecond,\r
+    GetLocalTime(&Sys);\r
+    Len += sprintf_s(szBuf, sizeof(szBuf),\r
+        "[%4d/%02d/%02d %02d:%02d:%02d.%03d] [%u] ",\r
+        Sys.wYear, Sys.wMonth, Sys.wDay,\r
+        Sys.wHour, Sys.wMinute, Sys.wSecond,\r
         Sys.wMilliseconds, PID);\r
 \r
-       va_start(Arg, Fmt);\r
-       Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);\r
-       va_end(Arg);\r
+    va_start(Arg, Fmt);\r
+    Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);\r
+    va_end(Arg);\r
 \r
     MUTEX_LOCK(g_vtoylog_mutex);\r
 \r
-    fopen_s(&File, "ventoy.log", "a+");\r
+    fopen_s(&File, LOG_FILE, "a+");\r
     if (File)\r
     {\r
         fwrite(szBuf, 1, Len, File);\r
@@ -77,226 +223,224 @@ void Log(const char *Fmt, ...)
 \r
 static int LoadNtDriver(const char *DrvBinPath)\r
 {\r
-       int i;\r
-       int rc = 0;\r
-       BOOL Ret;\r
-       DWORD Status;\r
-       SC_HANDLE hServiceMgr;\r
-       SC_HANDLE hService;\r
-       char name[256] = { 0 };\r
-\r
-       for (i = (int)strlen(DrvBinPath) - 1; i >= 0; i--)\r
-       {\r
-               if (DrvBinPath[i] == '\\' || DrvBinPath[i] == '/')\r
-               {\r
-                       sprintf_s(name, sizeof(name), "%s", DrvBinPath + i + 1);\r
-                       break;\r
-               }\r
-       }\r
-\r
-       Log("Load NT driver: %s %s", DrvBinPath, name);\r
-\r
-       hServiceMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
-       if (hServiceMgr == NULL)\r
-       {\r
-               Log("OpenSCManager failed Error:%u", GetLastError());\r
-               return 1;\r
-       }\r
-\r
-       Log("OpenSCManager OK");\r
-\r
-       hService = CreateServiceA(hServiceMgr,\r
-               name,\r
-               name,\r
-               SERVICE_ALL_ACCESS,\r
-               SERVICE_KERNEL_DRIVER,\r
-               SERVICE_DEMAND_START,\r
-               SERVICE_ERROR_NORMAL,\r
-               DrvBinPath,\r
-               NULL, NULL, NULL, NULL, NULL);\r
-       if (hService == NULL)\r
-       {\r
-               Status = GetLastError();\r
-               if (Status != ERROR_IO_PENDING && Status != ERROR_SERVICE_EXISTS)\r
-               {\r
-                       Log("CreateService failed v %u", Status);\r
-                       CloseServiceHandle(hServiceMgr);\r
-                       return 1;\r
-               }\r
-\r
-               hService = OpenServiceA(hServiceMgr, name, SERVICE_ALL_ACCESS);\r
-               if (hService == NULL)\r
-               {\r
-                       Log("OpenService failed %u", Status);\r
-                       CloseServiceHandle(hServiceMgr);\r
-                       return 1;\r
-               }\r
-       }\r
-\r
-       Log("CreateService imdisk OK");\r
-\r
-       Ret = StartServiceA(hService, 0, NULL);\r
-       if (Ret)\r
-       {\r
-               Log("StartService OK");\r
-       }\r
-       else\r
-       {\r
-               Status = GetLastError();\r
-               if (Status == ERROR_SERVICE_ALREADY_RUNNING)\r
-               {\r
-                       rc = 0;\r
-               }\r
-               else\r
-               {\r
-                       Log("StartService error  %u", Status);\r
-                       rc = 1;\r
-               }\r
-       }\r
-\r
-       CloseServiceHandle(hService);\r
-       CloseServiceHandle(hServiceMgr);\r
-\r
-       Log("Load NT driver %s", rc ? "failed" : "success");\r
-\r
-       return rc;\r
-}\r
+    int i;\r
+    int rc = 0;\r
+    BOOL Ret;\r
+    DWORD Status;\r
+    SC_HANDLE hServiceMgr;\r
+    SC_HANDLE hService;\r
+    char name[256] = { 0 };\r
 \r
-static int ReadWholeFile2Buf(const char *Fullpath, void **Data, DWORD *Size)\r
-{\r
-       int rc = 1;\r
-       DWORD FileSize;\r
-       DWORD dwSize;\r
-       HANDLE Handle;\r
-       BYTE *Buffer = NULL;\r
+    for (i = (int)strlen(DrvBinPath) - 1; i >= 0; i--)\r
+    {\r
+        if (DrvBinPath[i] == '\\' || DrvBinPath[i] == '/')\r
+        {\r
+            sprintf_s(name, sizeof(name), "%s", DrvBinPath + i + 1);\r
+            break;\r
+        }\r
+    }\r
 \r
-       Log("ReadWholeFile2Buf <%s>", Fullpath);\r
+    Log("Load NT driver: %s %s", DrvBinPath, name);\r
 \r
-       Handle = CreateFileA(Fullpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
-       if (Handle == INVALID_HANDLE_VALUE)\r
-       {\r
-               Log("Could not open the file<%s>, error:%u", Fullpath, GetLastError());\r
-               goto End;\r
-       }\r
+    hServiceMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
+    if (hServiceMgr == NULL)\r
+    {\r
+        Log("OpenSCManager failed Error:%u", GetLastError());\r
+        return 1;\r
+    }\r
 \r
-       FileSize = SetFilePointer(Handle, 0, NULL, FILE_END);\r
+    Log("OpenSCManager OK");\r
 \r
-       Buffer = malloc(FileSize);\r
-       if (!Buffer)\r
-       {\r
-               Log("Failed to alloc memory size:%u", FileSize);\r
-               goto End;\r
-       }\r
+    hService = CreateServiceA(hServiceMgr,\r
+        name,\r
+        name,\r
+        SERVICE_ALL_ACCESS,\r
+        SERVICE_KERNEL_DRIVER,\r
+        SERVICE_DEMAND_START,\r
+        SERVICE_ERROR_NORMAL,\r
+        DrvBinPath,\r
+        NULL, NULL, NULL, NULL, NULL);\r
+    if (hService == NULL)\r
+    {\r
+        Status = GetLastError();\r
+        if (Status != ERROR_IO_PENDING && Status != ERROR_SERVICE_EXISTS)\r
+        {\r
+            Log("CreateService failed v %u", Status);\r
+            CloseServiceHandle(hServiceMgr);\r
+            return 1;\r
+        }\r
 \r
-       SetFilePointer(Handle, 0, NULL, FILE_BEGIN);\r
-       if (!ReadFile(Handle, Buffer, FileSize, &dwSize, NULL))\r
-       {\r
-               Log("ReadFile failed, dwSize:%u  error:%u", dwSize, GetLastError());\r
-               goto End;\r
-       }\r
+        hService = OpenServiceA(hServiceMgr, name, SERVICE_ALL_ACCESS);\r
+        if (hService == NULL)\r
+        {\r
+            Log("OpenService failed %u", Status);\r
+            CloseServiceHandle(hServiceMgr);\r
+            return 1;\r
+        }\r
+    }\r
 \r
-       *Data = Buffer;\r
-       *Size = FileSize;\r
+    Log("CreateService imdisk OK");\r
 \r
-       Log("Success read file size:%u", FileSize);\r
+    Ret = StartServiceA(hService, 0, NULL);\r
+    if (Ret)\r
+    {\r
+        Log("StartService OK");\r
+    }\r
+    else\r
+    {\r
+        Status = GetLastError();\r
+        if (Status == ERROR_SERVICE_ALREADY_RUNNING)\r
+        {\r
+            rc = 0;\r
+        }\r
+        else\r
+        {\r
+            Log("StartService error  %u", Status);\r
+            rc = 1;\r
+        }\r
+    }\r
 \r
-       rc = 0;\r
+    CloseServiceHandle(hService);\r
+    CloseServiceHandle(hServiceMgr);\r
 \r
-End:\r
-       SAFE_CLOSE_HANDLE(Handle);\r
+    Log("Load NT driver %s", rc ? "failed" : "success");\r
 \r
-       return rc;\r
+    return rc;\r
 }\r
 \r
-static BOOL CheckPeHead(BYTE *Head)\r
+static int ReadWholeFile2Buf(const char *Fullpath, void **Data, DWORD *Size)\r
 {\r
-       UINT32 PeOffset;\r
+    int rc = 1;\r
+    DWORD FileSize;\r
+    DWORD dwSize;\r
+    HANDLE Handle;\r
+    BYTE *Buffer = NULL;\r
+\r
+    Log("ReadWholeFile2Buf <%s>", Fullpath);\r
+\r
+    Handle = CreateFileA(Fullpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+    if (Handle == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not open the file<%s>, error:%u", Fullpath, GetLastError());\r
+        goto End;\r
+    }\r
+\r
+    FileSize = SetFilePointer(Handle, 0, NULL, FILE_END);\r
 \r
-       if (Head[0] != 'M' || Head[1] != 'Z')\r
-       {\r
-               return FALSE;\r
-       }\r
+    Buffer = malloc(FileSize);\r
+    if (!Buffer)\r
+    {\r
+        Log("Failed to alloc memory size:%u", FileSize);\r
+        goto End;\r
+    }\r
+\r
+    SetFilePointer(Handle, 0, NULL, FILE_BEGIN);\r
+    if (!ReadFile(Handle, Buffer, FileSize, &dwSize, NULL))\r
+    {\r
+        Log("ReadFile failed, dwSize:%u  error:%u", dwSize, GetLastError());\r
+        goto End;\r
+    }\r
+\r
+    *Data = Buffer;\r
+    *Size = FileSize;\r
 \r
-       PeOffset = *(UINT32 *)(Head + 60);\r
-       if (*(UINT32 *)(Head + PeOffset) != 0x00004550)\r
-       {\r
-               return FALSE;\r
-       }\r
+    Log("Success read file size:%u", FileSize);\r
 \r
-       return TRUE;\r
+    rc = 0;\r
+\r
+End:\r
+    SAFE_CLOSE_HANDLE(Handle);\r
+\r
+    return rc;\r
 }\r
 \r
-static BOOL IsPe64(BYTE *buffer)\r
+static BOOL CheckPeHead(BYTE *Buffer, DWORD Size, DWORD Offset)\r
 {\r
-       DWORD pe_off;\r
+    UINT32 PeOffset;\r
+    BYTE *Head = NULL;\r
+    DWORD End;\r
+    ventoy_windows_data *pdata = NULL;\r
+\r
+    Head = Buffer + Offset;\r
+    pdata = (ventoy_windows_data *)Head;\r
+    Head += sizeof(ventoy_windows_data);\r
+\r
+    if (pdata->auto_install_script[0] && pdata->auto_install_len > 0)\r
+    {\r
+        End = Offset + sizeof(ventoy_windows_data) + pdata->auto_install_len + 60;\r
+        if (End < Size)\r
+        {\r
+            Head += pdata->auto_install_len;\r
+        }\r
+    }\r
 \r
-       if (!CheckPeHead(buffer))\r
-       {\r
-               return FALSE;\r
-       }\r
+    if (Head[0] != 'M' || Head[1] != 'Z')\r
+    {\r
+        return FALSE;\r
+    }\r
 \r
-       pe_off = *(UINT32 *)(buffer + 60);\r
-       if (*(UINT16 *)(buffer + pe_off + 24) == 0x020b)\r
-       {\r
-               return TRUE;\r
-       }\r
+    PeOffset = *(UINT32 *)(Head + 60);\r
+    if (*(UINT32 *)(Head + PeOffset) != 0x00004550)\r
+    {\r
+        return FALSE;\r
+    }\r
 \r
-       return FALSE;\r
+    return TRUE;\r
 }\r
 \r
 \r
 static BOOL CheckOsParam(ventoy_os_param *param)\r
 {\r
-       UINT32 i;\r
-       BYTE Sum = 0;\r
-\r
-       if (memcmp(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid)))\r
-       {\r
-               return FALSE;\r
-       }\r
-\r
-       for (i = 0; i < sizeof(ventoy_os_param); i++)\r
-       {\r
-               Sum += *((BYTE *)param + i);\r
-       }\r
-       \r
-       if (Sum)\r
-       {\r
-               return FALSE;\r
-       }\r
-\r
-       if (param->vtoy_img_location_addr % 4096)\r
-       {\r
-               return FALSE;\r
-       }\r
-\r
-       return TRUE;\r
+    UINT32 i;\r
+    BYTE Sum = 0;\r
+\r
+    if (memcmp(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid)))\r
+    {\r
+        return FALSE;\r
+    }\r
+\r
+    for (i = 0; i < sizeof(ventoy_os_param); i++)\r
+    {\r
+        Sum += *((BYTE *)param + i);\r
+    }\r
+    \r
+    if (Sum)\r
+    {\r
+        return FALSE;\r
+    }\r
+\r
+    if (param->vtoy_img_location_addr % 4096)\r
+    {\r
+        return FALSE;\r
+    }\r
+\r
+    return TRUE;\r
 }\r
 \r
 static int SaveBuffer2File(const char *Fullpath, void *Buffer, DWORD Length)\r
 {\r
-       int rc = 1;\r
-       DWORD dwSize;\r
-       HANDLE Handle;\r
+    int rc = 1;\r
+    DWORD dwSize;\r
+    HANDLE Handle;\r
 \r
-       Log("SaveBuffer2File <%s> len:%u", Fullpath, Length);\r
+    Log("SaveBuffer2File <%s> len:%u", Fullpath, Length);\r
 \r
-       Handle = CreateFileA(Fullpath, GENERIC_READ | GENERIC_WRITE,\r
-               FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);\r
-       if (Handle == INVALID_HANDLE_VALUE)\r
-       {\r
-               Log("Could not create new file, error:%u", GetLastError());\r
-               goto End;\r
-       }\r
+    Handle = CreateFileA(Fullpath, GENERIC_READ | GENERIC_WRITE,\r
+        FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);\r
+    if (Handle == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not create new file, error:%u", GetLastError());\r
+        goto End;\r
+    }\r
 \r
-       WriteFile(Handle, Buffer, Length, &dwSize, NULL);\r
+    WriteFile(Handle, Buffer, Length, &dwSize, NULL);\r
 \r
-       rc = 0;\r
+    rc = 0;\r
 \r
 End:\r
-       SAFE_CLOSE_HANDLE(Handle);\r
+    SAFE_CLOSE_HANDLE(Handle);\r
 \r
-       return rc;\r
+    return rc;\r
 }\r
 \r
 static int IsUTF8Encode(const char *src)\r
@@ -355,17 +499,17 @@ static BOOL IsDirExist(const char *Fmt, ...)
 \r
 static BOOL IsFileExist(const char *Fmt, ...)\r
 {\r
-       va_list Arg;\r
-       HANDLE hFile;\r
-       DWORD Attr;\r
+    va_list Arg;\r
+    HANDLE hFile;\r
+    DWORD Attr;\r
     BOOL bRet = FALSE;\r
     int UTF8 = 0;\r
-       CHAR FilePathA[MAX_PATH];\r
-       WCHAR FilePathW[MAX_PATH];\r
+    CHAR FilePathA[MAX_PATH];\r
+    WCHAR FilePathW[MAX_PATH];\r
 \r
-       va_start(Arg, Fmt);\r
-       vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);\r
-       va_end(Arg);\r
+    va_start(Arg, Fmt);\r
+    vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);\r
+    va_end(Arg);\r
 \r
     UTF8 = IsUTF8Encode(FilePathA);\r
 \r
@@ -378,12 +522,12 @@ static BOOL IsFileExist(const char *Fmt, ...)
     {\r
         hFile = CreateFileA(FilePathA, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);\r
     }\r
-       if (INVALID_HANDLE_VALUE == hFile)\r
-       {\r
+    if (INVALID_HANDLE_VALUE == hFile)\r
+    {\r
         goto out;\r
-       }\r
+    }\r
 \r
-       CloseHandle(hFile);\r
+    CloseHandle(hFile);\r
 \r
     if (UTF8)\r
     {\r
@@ -393,7 +537,7 @@ static BOOL IsFileExist(const char *Fmt, ...)
     {\r
         Attr = GetFileAttributesA(FilePathA);\r
     }\r
-       \r
+    \r
     if (Attr & FILE_ATTRIBUTE_DIRECTORY)\r
     {\r
         goto out;\r
@@ -406,62 +550,68 @@ out:
     return bRet;\r
 }\r
 \r
-static int GetPhyDiskUUID(const char LogicalDrive, UINT8 *UUID, DISK_EXTENT *DiskExtent)\r
+static int GetPhyDiskUUID(const char LogicalDrive, UINT8 *UUID, UINT32 *DiskSig, DISK_EXTENT *DiskExtent)\r
 {\r
-       BOOL Ret;\r
-       DWORD dwSize;\r
-       HANDLE Handle;\r
-       VOLUME_DISK_EXTENTS DiskExtents;\r
-       CHAR PhyPath[128];\r
-       UINT8 SectorBuf[512];\r
-\r
-       Log("GetPhyDiskUUID %C", LogicalDrive);\r
-\r
-       sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);\r
-       Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
-       if (Handle == INVALID_HANDLE_VALUE)\r
-       {\r
-               Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
-               return 1;\r
-       }\r
-\r
-       Ret = DeviceIoControl(Handle,\r
-               IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,\r
-               NULL,\r
-               0,\r
-               &DiskExtents,\r
-               (DWORD)(sizeof(DiskExtents)),\r
-               (LPDWORD)&dwSize,\r
-               NULL);\r
-       if (!Ret || DiskExtents.NumberOfDiskExtents == 0)\r
-       {\r
-               Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u", GetLastError());\r
-               CloseHandle(Handle);\r
-               return 1;\r
-       }\r
-       CloseHandle(Handle);\r
-\r
-       memcpy(DiskExtent, DiskExtents.Extents, sizeof(DiskExtent));\r
-       Log("%C: is in PhysicalDrive%d ", LogicalDrive, DiskExtents.Extents[0].DiskNumber);\r
-\r
-       sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);\r
-       Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
-       if (Handle == INVALID_HANDLE_VALUE)\r
-       {\r
-               Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
-               return 1;\r
-       }\r
-\r
-       if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))\r
-       {\r
-               Log("ReadFile failed, dwSize:%u  error:%u", dwSize, GetLastError());\r
-               CloseHandle(Handle);\r
-               return 1;\r
-       }\r
-       \r
-       memcpy(UUID, SectorBuf + 0x180, 16);\r
-       CloseHandle(Handle);\r
-       return 0;\r
+    BOOL Ret;\r
+    DWORD dwSize;\r
+    HANDLE Handle;\r
+    VOLUME_DISK_EXTENTS DiskExtents;\r
+    CHAR PhyPath[128];\r
+    UINT8 SectorBuf[512];\r
+\r
+    Log("GetPhyDiskUUID %C", LogicalDrive);\r
+\r
+    sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);\r
+    Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+    if (Handle == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
+        return 1;\r
+    }\r
+\r
+    Ret = DeviceIoControl(Handle,\r
+        IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,\r
+        NULL,\r
+        0,\r
+        &DiskExtents,\r
+        (DWORD)(sizeof(DiskExtents)),\r
+        (LPDWORD)&dwSize,\r
+        NULL);\r
+    if (!Ret || DiskExtents.NumberOfDiskExtents == 0)\r
+    {\r
+        Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u", GetLastError());\r
+        CloseHandle(Handle);\r
+        return 1;\r
+    }\r
+    CloseHandle(Handle);\r
+\r
+    memcpy(DiskExtent, DiskExtents.Extents, sizeof(DISK_EXTENT));\r
+    Log("%C: is in PhysicalDrive%d Offset:%llu", LogicalDrive, DiskExtents.Extents[0].DiskNumber, \r
+        (ULONGLONG)(DiskExtents.Extents[0].StartingOffset.QuadPart));\r
+\r
+    sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);\r
+    Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+    if (Handle == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
+        return 1;\r
+    }\r
+\r
+    if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))\r
+    {\r
+        Log("ReadFile failed, dwSize:%u  error:%u", dwSize, GetLastError());\r
+        CloseHandle(Handle);\r
+        return 1;\r
+    }\r
+    \r
+    memcpy(UUID, SectorBuf + 0x180, 16);\r
+    if (DiskSig)\r
+    {\r
+        memcpy(DiskSig, SectorBuf + 0x1B8, 4);\r
+    }\r
+\r
+    CloseHandle(Handle);\r
+    return 0;\r
 }\r
 \r
 static int VentoyMountAnywhere(HANDLE Handle)\r
@@ -521,7 +671,7 @@ int VentoyMountY(HANDLE Handle)
 \r
     for (i = 0; physicalDriveName[i]; i++)\r
     {\r
-        physicalDriveNameA[i] = toupper((CHAR)(physicalDriveName[i]));\r
+        physicalDriveNameA[i] = (CHAR)toupper((CHAR)(physicalDriveName[i]));\r
     }\r
 \r
     Log("physicalDriveNameA=<%s>", physicalDriveNameA);\r
@@ -546,8 +696,10 @@ int VentoyMountY(HANDLE Handle)
     return bRet ? 0 : 1;\r
 }\r
 \r
-static BOOL VentoyNeedMountY(const char *IsoPath)\r
+static BOOL VentoyAPINeedMountY(const char *IsoPath)\r
 {\r
+    (void)IsoPath;\r
+\r
     /* TBD */\r
     return FALSE;\r
 }\r
@@ -569,7 +721,7 @@ static int VentoyAttachVirtualDisk(HANDLE Handle, const char *IsoPath)
         DriveYFree = 1;\r
     }\r
 \r
-    if (DriveYFree && VentoyNeedMountY(IsoPath))\r
+    if (DriveYFree && VentoyAPINeedMountY(IsoPath))\r
     {\r
         return VentoyMountY(Handle);\r
     }\r
@@ -581,56 +733,76 @@ static int VentoyAttachVirtualDisk(HANDLE Handle, const char *IsoPath)
 \r
 int VentoyMountISOByAPI(const char *IsoPath)\r
 {\r
-       HANDLE Handle;\r
-       DWORD Status;\r
-       WCHAR wFilePath[512] = { 0 };\r
-       VIRTUAL_STORAGE_TYPE StorageType;\r
-       OPEN_VIRTUAL_DISK_PARAMETERS OpenParameters;\r
+    int i;\r
+    HANDLE Handle;\r
+    DWORD Status;\r
+    WCHAR wFilePath[512] = { 0 };\r
+    VIRTUAL_STORAGE_TYPE StorageType;\r
+    OPEN_VIRTUAL_DISK_PARAMETERS OpenParameters;\r
 \r
-       Log("VentoyMountISOByAPI <%s>", IsoPath);\r
+    Log("VentoyMountISOByAPI <%s>", IsoPath);\r
 \r
     if (IsUTF8Encode(IsoPath))\r
     {\r
+        Log("This is UTF8 encoding");\r
         MultiByteToWideChar(CP_UTF8, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));\r
     }\r
     else\r
     {\r
+        Log("This is ANSI encoding");\r
         MultiByteToWideChar(CP_ACP, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));\r
     }\r
 \r
-       memset(&StorageType, 0, sizeof(StorageType));\r
-       memset(&OpenParameters, 0, sizeof(OpenParameters));\r
-       \r
-       OpenParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1;\r
+    memset(&StorageType, 0, sizeof(StorageType));\r
+    memset(&OpenParameters, 0, sizeof(OpenParameters));\r
+    \r
+    OpenParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1;\r
+\r
+    for (i = 0; i < 10; i++)\r
+    {\r
+        Status = OpenVirtualDisk(&StorageType, wFilePath, VIRTUAL_DISK_ACCESS_READ, 0, &OpenParameters, &Handle);\r
+        if (ERROR_FILE_NOT_FOUND == Status || ERROR_PATH_NOT_FOUND == Status)\r
+        {\r
+            Log("OpenVirtualDisk ErrorCode:%u, now wait and retry...", Status);\r
+            Sleep(1000);\r
+        }\r
+        else\r
+        {\r
+            if (ERROR_SUCCESS == Status)\r
+            {\r
+                Log("OpenVirtualDisk success");\r
+            }\r
+            else if (ERROR_VIRTDISK_PROVIDER_NOT_FOUND == Status)\r
+            {\r
+                Log("VirtualDisk for ISO file is not supported in current system");\r
+            }\r
+            else\r
+            {\r
+                Log("Failed to open virtual disk ErrorCode:%u", Status);\r
+            }\r
+            break;\r
+        }\r
+    }\r
 \r
-       Status = OpenVirtualDisk(&StorageType, wFilePath, VIRTUAL_DISK_ACCESS_READ, 0, &OpenParameters, &Handle);\r
-       if (Status != ERROR_SUCCESS)\r
-       {\r
-               if (ERROR_VIRTDISK_PROVIDER_NOT_FOUND == Status)\r
-               {\r
-                       Log("VirtualDisk for ISO file is not supported in current system");\r
-               }\r
-               else\r
-               {\r
-                       Log("Failed to open virtual disk ErrorCode:%u", Status);\r
-               }\r
-               return 1;\r
-       }\r
+    if (Status != ERROR_SUCCESS)\r
+    {\r
+        return 1;\r
+    }\r
 \r
-       Log("OpenVirtualDisk success");\r
+    Log("OpenVirtualDisk success");\r
 \r
     Status = VentoyAttachVirtualDisk(Handle, IsoPath);\r
-       if (Status != ERROR_SUCCESS)\r
-       {\r
-               Log("Failed to attach virtual disk ErrorCode:%u", Status);\r
-               CloseHandle(Handle);\r
-               return 1;\r
-       }\r
+    if (Status != ERROR_SUCCESS)\r
+    {\r
+        Log("Failed to attach virtual disk ErrorCode:%u", Status);\r
+        CloseHandle(Handle);\r
+        return 1;\r
+    }\r
 \r
     Log("VentoyAttachVirtualDisk success");\r
 \r
-       CloseHandle(Handle);\r
-       return 0;\r
+    CloseHandle(Handle);\r
+    return 0;\r
 }\r
 \r
 \r
@@ -639,230 +811,394 @@ static UINT64 g_Part2StartSec;
 \r
 static int CopyFileFromFatDisk(const CHAR* SrcFile, const CHAR *DstFile)\r
 {\r
-       int rc = 1;\r
-       int size = 0;\r
-       char *buf = NULL;\r
-       void *flfile = NULL;\r
-\r
-       Log("CopyFileFromFatDisk (%s)==>(%s)", SrcFile, DstFile);\r
-\r
-       flfile = fl_fopen(SrcFile, "rb");\r
-       if (flfile)\r
-       {\r
-               fl_fseek(flfile, 0, SEEK_END);\r
-               size = (int)fl_ftell(flfile);\r
-               fl_fseek(flfile, 0, SEEK_SET);\r
-\r
-               buf = (char *)malloc(size);\r
-               if (buf)\r
-               {\r
-                       fl_fread(buf, 1, size, flfile);\r
-\r
-                       rc = 0;\r
-                       SaveBuffer2File(DstFile, buf, size);\r
-                       free(buf);\r
-               }\r
-\r
-               fl_fclose(flfile);\r
-       }\r
-\r
-       return rc;\r
-}\r
+    int rc = 1;\r
+    int size = 0;\r
+    char *buf = NULL;\r
+    void *flfile = NULL;\r
+\r
+    Log("CopyFileFromFatDisk (%s)==>(%s)", SrcFile, DstFile);\r
+\r
+    flfile = fl_fopen(SrcFile, "rb");\r
+    if (flfile)\r
+    {\r
+        fl_fseek(flfile, 0, SEEK_END);\r
+        size = (int)fl_ftell(flfile);\r
+        fl_fseek(flfile, 0, SEEK_SET);\r
+\r
+        buf = (char *)malloc(size);\r
+        if (buf)\r
+        {\r
+            fl_fread(buf, 1, size, flfile);\r
+\r
+            rc = 0;\r
+            SaveBuffer2File(DstFile, buf, size);\r
+            free(buf);\r
+        }\r
+\r
+        fl_fclose(flfile);\r
+    }\r
+\r
+    return rc;\r
+}\r
 \r
 static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)\r
 {\r
-       DWORD dwSize;\r
-       BOOL bRet;\r
-       DWORD ReadSize;\r
-       LARGE_INTEGER liCurrentPosition;\r
+    DWORD dwSize;\r
+    BOOL bRet;\r
+    DWORD ReadSize;\r
+    LARGE_INTEGER liCurrentPosition;\r
 \r
-       liCurrentPosition.QuadPart = Sector + g_Part2StartSec;\r
-       liCurrentPosition.QuadPart *= 512;\r
-       SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);\r
+    liCurrentPosition.QuadPart = Sector + g_Part2StartSec;\r
+    liCurrentPosition.QuadPart *= 512;\r
+    SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);\r
 \r
-       ReadSize = (DWORD)(SectorCount * 512);\r
+    ReadSize = (DWORD)(SectorCount * 512);\r
 \r
-       bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);\r
-       if (bRet == FALSE || dwSize != ReadSize)\r
-       {\r
-               Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u\n", bRet, ReadSize, dwSize, GetLastError());\r
-       }\r
+    bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);\r
+    if (bRet == FALSE || dwSize != ReadSize)\r
+    {\r
+        Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u", bRet, ReadSize, dwSize, GetLastError());\r
+    }\r
+\r
+    return 1;\r
+}\r
+\r
+static BOOL Is2K10PE(void)\r
+{\r
+    BOOL bRet = FALSE;\r
+    FILE *fp = NULL;\r
+    CHAR szLine[1024];\r
+\r
+    fopen_s(&fp, "X:\\Windows\\System32\\PECMD.INI", "r");\r
+    if (!fp)\r
+    {\r
+        return FALSE;\r
+    }\r
+\r
+    memset(szLine, 0, sizeof(szLine));\r
+    while (fgets(szLine, sizeof(szLine) - 1, fp))\r
+    {\r
+        if (strstr(szLine, "2k10\\"))\r
+        {\r
+            bRet = TRUE;\r
+            break;\r
+        }\r
+    }\r
 \r
-       return 1;\r
+    fclose(fp);\r
+    return bRet;\r
 }\r
 \r
-static CHAR GetMountLogicalDrive(void)\r
+static CHAR GetIMDiskMountLogicalDrive(void)\r
 {\r
-       CHAR Letter = 'Y';\r
-       DWORD Drives;\r
-       DWORD Mask = 0x1000000;\r
+    CHAR Letter = 'Y';\r
+    DWORD Drives;\r
+    DWORD Mask = 0x1000000;\r
+\r
+    // fixed use M as mountpoint for 2K10 PE\r
+    if (Is2K10PE())\r
+    {\r
+        Log("Use M: for 2K10 PE");\r
+        return 'M';\r
+    }\r
 \r
-       Drives = GetLogicalDrives();\r
+    Drives = GetLogicalDrives();\r
     Log("Drives=0x%x", Drives);\r
     \r
-       while (Mask)\r
-       {\r
-               if ((Drives & Mask) == 0)\r
-               {\r
-                       break;\r
-               }\r
-\r
-               Letter--;\r
-               Mask >>= 1;\r
-       }\r
-\r
-       return Letter;\r
+    while (Mask)\r
+    {\r
+        if ((Drives & Mask) == 0)\r
+        {\r
+            break;\r
+        }\r
+\r
+        Letter--;\r
+        Mask >>= 1;\r
+    }\r
+\r
+    return Letter;\r
 }\r
 \r
 UINT64 GetVentoyEfiPartStartSector(HANDLE hDrive)\r
 {\r
-       BOOL bRet;\r
-       DWORD dwSize; \r
-       MBR_HEAD MBR;   \r
-       VTOY_GPT_INFO *pGpt = NULL;\r
-       UINT64 StartSector = 0;\r
-\r
-       SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
-\r
-       bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);\r
-       Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);\r
-\r
-       if ((!bRet) || (dwSize != sizeof(MBR)))\r
-       {\r
-               0;\r
-       }\r
-\r
-       if (MBR.PartTbl[0].FsFlag == 0xEE)\r
-       {\r
-               Log("GPT partition style");\r
-\r
-               pGpt = malloc(sizeof(VTOY_GPT_INFO));\r
-               if (!pGpt)\r
-               {\r
-                       return 0;\r
-               }\r
-\r
-               SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
-               bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);            \r
-               if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))\r
-               {\r
-                       Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);\r
-                       return 0;\r
-               }\r
-\r
-               StartSector = pGpt->PartTbl[1].StartLBA;\r
-               free(pGpt);\r
-       }\r
-       else\r
-       {\r
-               Log("MBR partition style");\r
-               StartSector = MBR.PartTbl[1].StartSectorId;\r
-       }\r
-\r
-       Log("GetVentoyEfiPart StartSector: %llu", StartSector);\r
-       return StartSector;\r
+    BOOL bRet;\r
+    DWORD dwSize; \r
+    MBR_HEAD MBR;   \r
+    VTOY_GPT_INFO *pGpt = NULL;\r
+    UINT64 StartSector = 0;\r
+\r
+    SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+\r
+    bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);\r
+    Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);\r
+\r
+    if ((!bRet) || (dwSize != sizeof(MBR)))\r
+    {\r
+        0;\r
+    }\r
+\r
+    if (MBR.PartTbl[0].FsFlag == 0xEE)\r
+    {\r
+        Log("GPT partition style");\r
+\r
+        pGpt = malloc(sizeof(VTOY_GPT_INFO));\r
+        if (!pGpt)\r
+        {\r
+            return 0;\r
+        }\r
+\r
+        SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+        bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);        \r
+        if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))\r
+        {\r
+            Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);\r
+            return 0;\r
+        }\r
+\r
+        StartSector = pGpt->PartTbl[1].StartLBA;\r
+        free(pGpt);\r
+    }\r
+    else\r
+    {\r
+        Log("MBR partition style");\r
+        StartSector = MBR.PartTbl[1].StartSectorId;\r
+    }\r
+\r
+    Log("GetVentoyEfiPart StartSector: %llu", StartSector);\r
+    return StartSector;\r
 }\r
 \r
-int VentoyMountISOByImdisk(const char *IsoPath, DWORD PhyDrive)\r
+static int VentoyCopyImdisk(DWORD PhyDrive, CHAR *ImPath)\r
 {\r
-       int rc = 1;\r
-       BOOL bRet;\r
-       CHAR Letter;\r
-       DWORD dwBytes;\r
-       HANDLE hDrive;\r
-       CHAR PhyPath[MAX_PATH];\r
-       WCHAR PhyPathW[MAX_PATH];\r
-       PROCESS_INFORMATION Pi;\r
-       GET_LENGTH_INFORMATION LengthInfo;\r
-\r
-       Log("VentoyMountISOByImdisk %s", IsoPath);\r
-\r
-       sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", PhyDrive);\r
+    int rc = 1;\r
+    BOOL bRet;\r
+    DWORD dwBytes;\r
+    HANDLE hDrive;\r
+    CHAR PhyPath[MAX_PATH];\r
+    GET_LENGTH_INFORMATION LengthInfo;\r
+\r
+    if (IsFileExist("X:\\Windows\\System32\\imdisk.exe"))\r
+    {\r
+        Log("imdisk.exe already exist, no need to copy...");\r
+        strcpy_s(ImPath, MAX_PATH, "imdisk.exe");        \r
+        return 0;\r
+    }\r
+\r
+    if (IsFileExist("X:\\Windows\\System32\\ventoy\\imdisk.exe"))\r
+    {\r
+        Log("imdisk.exe already copied, no need to copy...");\r
+        strcpy_s(ImPath, MAX_PATH, "ventoy\\imdisk.exe");\r
+        return 0;\r
+    }\r
+\r
+    sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", PhyDrive);\r
     hDrive = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
-       if (hDrive == INVALID_HANDLE_VALUE)\r
-       {\r
-               Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
-               goto End;\r
-       }\r
-\r
-       bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);\r
-       if (!bRet)\r
-       {\r
-               Log("Could not get phy disk %s size, error:%u", PhyPath, GetLastError());\r
-               goto End;\r
-       }\r
-\r
-       g_FatPhyDrive = hDrive;\r
-       g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);\r
-\r
-       Log("Parse FAT fs...");\r
-\r
-       fl_init();\r
-\r
-       if (0 == fl_attach_media(VentoyFatDiskRead, NULL))\r
-       {\r
-               if (g_64bit_system)\r
-               {\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.sys", "ventoy\\imdisk.sys");\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.exe", "ventoy\\imdisk.exe");\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.cpl", "ventoy\\imdisk.cpl");\r
-               }\r
-               else\r
-               {\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.sys", "ventoy\\imdisk.sys");\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.exe", "ventoy\\imdisk.exe");\r
-                       CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.cpl", "ventoy\\imdisk.cpl");\r
-               }\r
-               \r
-               GetCurrentDirectoryA(sizeof(PhyPath), PhyPath);\r
-               strcat_s(PhyPath, sizeof(PhyPath), "\\ventoy\\imdisk.sys");\r
-\r
-               if (LoadNtDriver(PhyPath) == 0)\r
-               {\r
-                       rc = 0;\r
-\r
-                       Letter = GetMountLogicalDrive();\r
-            sprintf_s(PhyPath, sizeof(PhyPath), "ventoy\\imdisk.exe -a -o ro -f \"%s\" -m %C:", IsoPath, Letter);\r
-            Log("mount iso to %C: use imdisk cmd <%s>", Letter, PhyPath);\r
-\r
-            if (IsUTF8Encode(IsoPath))\r
-            {\r
-                STARTUPINFOW Si;\r
-                GetStartupInfoW(&Si);\r
-                Si.dwFlags |= STARTF_USESHOWWINDOW;\r
-                Si.wShowWindow = SW_HIDE;\r
+    if (hDrive == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
+        goto End;\r
+    }\r
 \r
-                Utf8ToUtf16(PhyPath, PhyPathW);\r
-                CreateProcessW(NULL, PhyPathW, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+    bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);\r
+    if (!bRet)\r
+    {\r
+        Log("Could not get phy disk %s size, error:%u", PhyPath, GetLastError());\r
+        goto End;\r
+    }\r
 \r
-                Log("This is UTF8 encoding");\r
-            }\r
-            else\r
-            {\r
-                STARTUPINFOA Si;\r
-                GetStartupInfoA(&Si);\r
-                Si.dwFlags |= STARTF_USESHOWWINDOW;\r
-                Si.wShowWindow = SW_HIDE;\r
+    g_FatPhyDrive = hDrive;\r
+    g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);\r
+\r
+    Log("Parse FAT fs...");\r
 \r
-                CreateProcessA(NULL, PhyPath, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+    fl_init();\r
 \r
-                Log("This is ANSI encoding");\r
-            }\r
+    if (0 == fl_attach_media(VentoyFatDiskRead, NULL))\r
+    {\r
+        if (g_system_bit == 64)\r
+        {\r
+            CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.sys", "ventoy\\imdisk.sys");\r
+            CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.exe", "ventoy\\imdisk.exe");\r
+            CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.cpl", "ventoy\\imdisk.cpl");\r
+        }\r
+        else\r
+        {\r
+            CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.sys", "ventoy\\imdisk.sys");\r
+            CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.exe", "ventoy\\imdisk.exe");\r
+            CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.cpl", "ventoy\\imdisk.cpl");\r
+        }\r
 \r
-                       WaitForSingleObject(Pi.hProcess, INFINITE);\r
-               }\r
-       }\r
-       fl_shutdown();\r
+        GetCurrentDirectoryA(sizeof(PhyPath), PhyPath);\r
+        strcat_s(PhyPath, sizeof(PhyPath), "\\ventoy\\imdisk.sys");\r
+\r
+        if (LoadNtDriver(PhyPath) == 0)\r
+        {        \r
+            strcpy_s(ImPath, MAX_PATH, "ventoy\\imdisk.exe");\r
+            rc = 0;\r
+        }\r
+    }\r
+    fl_shutdown();\r
 \r
 End:\r
 \r
-       SAFE_CLOSE_HANDLE(hDrive);\r
+    SAFE_CLOSE_HANDLE(hDrive);\r
+\r
+    return rc;\r
+}\r
+\r
+static int VentoyRunImdisk(const char *IsoPath, const char *imdiskexe)\r
+{\r
+    CHAR Letter;\r
+    CHAR Cmdline[512];\r
+    WCHAR CmdlineW[512];\r
+    PROCESS_INFORMATION Pi;\r
+\r
+    Log("VentoyRunImdisk <%s> <%s>", IsoPath, imdiskexe);\r
+\r
+    Letter = GetIMDiskMountLogicalDrive();\r
+    sprintf_s(Cmdline, sizeof(Cmdline), "%s -a -o ro -f \"%s\" -m %C:", imdiskexe, IsoPath, Letter);\r
+    Log("mount iso to %C: use imdisk cmd <%s>", Letter, Cmdline);\r
+\r
+    if (IsUTF8Encode(IsoPath))\r
+    {\r
+        STARTUPINFOW Si;\r
+        GetStartupInfoW(&Si);\r
+        Si.dwFlags |= STARTF_USESHOWWINDOW;\r
+        Si.wShowWindow = SW_HIDE;\r
+\r
+        Utf8ToUtf16(Cmdline, CmdlineW);\r
+        CreateProcessW(NULL, CmdlineW, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
 \r
-       return rc;\r
+        Log("This is UTF8 encoding");\r
+    }\r
+    else\r
+    {\r
+        STARTUPINFOA Si;\r
+        GetStartupInfoA(&Si);\r
+        Si.dwFlags |= STARTF_USESHOWWINDOW;\r
+        Si.wShowWindow = SW_HIDE;\r
+\r
+        CreateProcessA(NULL, Cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+\r
+        Log("This is ANSI encoding");\r
+    }\r
+\r
+    Log("Wait for imdisk process ...");\r
+    WaitForSingleObject(Pi.hProcess, INFINITE);\r
+    Log("imdisk process finished");\r
+\r
+    return 0;\r
+}\r
+\r
+int VentoyMountISOByImdisk(const char *IsoPath, DWORD PhyDrive)\r
+{\r
+    int rc = 1;\r
+    CHAR ImPath[MAX_PATH];\r
+\r
+    Log("VentoyMountISOByImdisk %s", IsoPath);\r
+\r
+    if (0 == VentoyCopyImdisk(PhyDrive, ImPath))\r
+    {\r
+        VentoyRunImdisk(IsoPath, ImPath);\r
+        rc = 0;\r
+    }\r
+\r
+    return rc;\r
+}\r
+\r
+static int GetIsoId(CONST CHAR *IsoPath, IsoId *ids)\r
+{\r
+    int i;\r
+    int n = 0;\r
+    HANDLE hFile;\r
+    DWORD dwSize = 0;\r
+    BOOL bRet[8];\r
+\r
+    hFile = CreateFileA(IsoPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\r
+    if (hFile == INVALID_HANDLE_VALUE)\r
+    {\r
+        return 1;\r
+    }\r
+\r
+    SetFilePointer(hFile, 2048 * 16 + 8, NULL, FILE_BEGIN);\r
+    bRet[n++] = ReadFile(hFile, ids->SystemId, 32, &dwSize, NULL);\r
+    \r
+    SetFilePointer(hFile, 2048 * 16 + 40, NULL, FILE_BEGIN);\r
+    bRet[n++] = ReadFile(hFile, ids->VolumeId, 32, &dwSize, NULL);\r
+\r
+    SetFilePointer(hFile, 2048 * 16 + 318, NULL, FILE_BEGIN);\r
+    bRet[n++] = ReadFile(hFile, ids->PulisherId, 128, &dwSize, NULL);\r
+\r
+    SetFilePointer(hFile, 2048 * 16 + 446, NULL, FILE_BEGIN);\r
+    bRet[n++] = ReadFile(hFile, ids->PreparerId, 128, &dwSize, NULL);\r
+\r
+    CloseHandle(hFile);\r
+\r
+\r
+    for (i = 0; i < n; i++)\r
+    {\r
+        if (bRet[i] == FALSE)\r
+        {\r
+            return 1;\r
+        }\r
+    }\r
+\r
+\r
+    TrimString(ids->SystemId, FALSE);\r
+    TrimString(ids->VolumeId, FALSE);\r
+    TrimString(ids->PulisherId, FALSE);\r
+    TrimString(ids->PreparerId, FALSE);\r
+\r
+    Log("ISO ID: System<%s> Volume<%s> Pulisher<%s> Preparer<%s>", \r
+        ids->SystemId, ids->VolumeId, ids->PulisherId, ids->PreparerId);\r
+\r
+    return 0;\r
+}\r
+\r
+static int CheckSkipMountIso(CONST CHAR *IsoPath)\r
+{\r
+    BOOL InRoot = FALSE;\r
+    int slashcnt = 0;\r
+    CONST CHAR *p = NULL;\r
+    IsoId ID;\r
+\r
+    // C:\\xxx\r
+    for (p = IsoPath; *p; p++)\r
+    {\r
+        if (*p == '\\' || *p == '/')\r
+        {\r
+            slashcnt++;\r
+        }\r
+    }\r
+\r
+    if (slashcnt == 2)\r
+    {\r
+        InRoot = TRUE;\r
+    }\r
+\r
+    memset(&ID, 0, sizeof(ID));\r
+    if (GetIsoId(IsoPath, &ID))\r
+    {\r
+        return 0;\r
+    }\r
+\r
+    //Bob.Ombs.Modified.Win10PEx64.iso will auto find ISO file in root, so we can skip the mount\r
+    if (InRoot && strcmp(ID.VolumeId, "Modified-Win10PEx64") == 0)\r
+    {\r
+        return 1;\r
+    }\r
+\r
+    return 0;\r
 }\r
 \r
 static int MountIsoFile(CONST CHAR *IsoPath, DWORD PhyDrive)\r
 {\r
+    if (CheckSkipMountIso(IsoPath))\r
+    {\r
+        Log("Skip mount ISO file for <%s>", IsoPath);\r
+        return 0;\r
+    }\r
+\r
     if (IsWindows8OrGreater())\r
     {\r
         Log("This is Windows 8 or latter...");\r
@@ -1011,11 +1347,31 @@ static BOOL check_tar_archive(const char *archive, CHAR *tarName)
     return FALSE;\r
 }\r
 \r
+static UCHAR *g_unxz_buffer = NULL;\r
+static int g_unxz_len = 0;\r
+\r
+static void unxz_error(char *x)\r
+{\r
+    Log("%s", x);\r
+}\r
+\r
+static int unxz_flush(void *src, unsigned int size)\r
+{\r
+    memcpy(g_unxz_buffer + g_unxz_len, src, size);\r
+    g_unxz_len += (int)size;\r
+\r
+    return (int)size;\r
+}\r
+\r
 static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)\r
 {\r
     int rc = 1;\r
+    int writelen = 0;\r
+    UCHAR *Buffer = NULL;\r
+    UCHAR *RawBuffer = NULL;\r
     BOOL bRet;\r
     DWORD dwBytes;\r
+    DWORD dwSize;\r
     HANDLE hDrive;\r
     HANDLE hOut;\r
     DWORD flags = CREATE_NO_WINDOW;\r
@@ -1045,7 +1401,7 @@ static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)
     }\r
 \r
     g_FatPhyDrive = hDrive;\r
-       g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);\r
+    g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);\r
 \r
     Log("Parse FAT fs...");\r
 \r
@@ -1053,13 +1409,42 @@ static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)
 \r
     if (0 == fl_attach_media(VentoyFatDiskRead, NULL))\r
     {\r
-        if (g_64bit_system)\r
+        if (g_system_bit == 64)\r
         {\r
-            CopyFileFromFatDisk("/ventoy/7z/64/7za.exe", "ventoy\\7za.exe");\r
+            CopyFileFromFatDisk("/ventoy/7z/64/7za.xz", "ventoy\\7za.xz");\r
         }\r
         else\r
         {\r
-            CopyFileFromFatDisk("/ventoy/7z/32/7za.exe", "ventoy\\7za.exe");\r
+            CopyFileFromFatDisk("/ventoy/7z/32/7za.xz", "ventoy\\7za.xz");\r
+        }\r
+\r
+        ReadWholeFile2Buf("ventoy\\7za.xz", &Buffer, &dwSize);\r
+        Log("7za.xz file size:%u", dwSize);\r
+\r
+        RawBuffer = malloc(SIZE_1MB * 4);\r
+        if (RawBuffer)\r
+        {\r
+            g_unxz_buffer = RawBuffer;\r
+            g_unxz_len = 0;\r
+            unxz(Buffer, (int)dwSize, NULL, unxz_flush, NULL, &writelen, unxz_error);\r
+            if (writelen == (int)dwSize)\r
+            {\r
+                Log("Decompress success 7za.xz(%u) ---> 7za.exe(%d)", dwSize, g_unxz_len);\r
+            }\r
+            else\r
+            {\r
+                Log("Decompress failed 7za.xz(%u) ---> 7za.exe(%u)", dwSize, dwSize);\r
+            }\r
+\r
+            SaveBuffer2File("ventoy\\7za.exe", RawBuffer, (DWORD)g_unxz_len);\r
+\r
+            g_unxz_buffer = NULL;\r
+            g_unxz_len = 0;\r
+            free(RawBuffer);\r
+        }\r
+        else\r
+        {\r
+            Log("Failed to alloc 4MB memory");\r
         }\r
 \r
         sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", archive);\r
@@ -1115,105 +1500,898 @@ End:
     return rc;\r
 }\r
 \r
-static int ProcessUnattendedInstallation(const char *script)\r
+static int UnattendNeedVarExpand(const char *script)\r
 {\r
-    DWORD dw;\r
-    HKEY hKey;\r
-    LSTATUS Ret;\r
-    CHAR Letter;\r
-    CHAR CurDir[MAX_PATH];\r
+    FILE *fp = NULL;\r
+    char szLine[4096];\r
 \r
-    Log("Copy unattended XML ...");\r
-    \r
-    GetCurrentDirectory(sizeof(CurDir), CurDir);\r
-    Letter = CurDir[0];\r
-    if ((Letter >= 'A' && Letter <= 'Z') || (Letter >= 'a' && Letter <= 'z'))\r
-    {\r
-        Log("Current Drive Letter: %C", Letter);\r
-    }\r
-    else\r
+    fopen_s(&fp, script, "r");\r
+    if (!fp)\r
     {\r
-        Letter = 'X';\r
+        return 0;\r
     }\r
-    \r
-    sprintf_s(CurDir, sizeof(CurDir), "%C:\\Autounattend.xml", Letter);\r
-    Log("Copy file <%s> --> <%s>", script, CurDir);\r
-    CopyFile(script, CurDir, FALSE);\r
 \r
-    Ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw);\r
-    if (ERROR_SUCCESS == Ret)\r
+    szLine[0] = szLine[4095] = 0;\r
+    \r
+    while (fgets(szLine, sizeof(szLine) - 1, fp))\r
     {\r
-        Ret = RegSetValueEx(hKey, "UnattendFile", 0, REG_SZ, CurDir, (DWORD)(strlen(CurDir) + 1));\r
+        if (strstr(szLine, "$$VT_"))\r
+        {\r
+            fclose(fp);\r
+            return 1;\r
+        }\r
+    \r
+        szLine[0] = szLine[4095] = 0;\r
     }\r
-\r
+    \r
+    fclose(fp);\r
     return 0;\r
 }\r
 \r
-static int VentoyHook(ventoy_os_param *param)\r
+static int ExpandSingleVar(VarDiskInfo *pDiskInfo, int DiskNum, const char *var, char *value, int len)\r
 {\r
-    int rc;\r
-       CHAR Letter = 'A';\r
-       DISK_EXTENT DiskExtent;\r
-       DWORD Drives = GetLogicalDrives();\r
-       UINT8 UUID[16];\r
-       CHAR IsoPath[MAX_PATH];\r
-\r
-       Log("Logical Drives=0x%x Path:<%s>", Drives, param->vtoy_img_path);\r
+    int i;\r
+    int index = -1;\r
+    UINT64 uiDst = 0;\r
+    UINT64 uiDelta = 0;\r
+    UINT64 uiMaxSize = 0;\r
+    UINT64 uiMaxDelta = ULLONG_MAX;\r
 \r
-    if (IsUTF8Encode(param->vtoy_img_path))\r
+    value[0] = 0;\r
+    \r
+    if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONVTOY") == 0)\r
     {\r
-        Log("This file is UTF8 encoding\n");\r
+        for (i = 0; i < DiskNum; i++)\r
+        {\r
+            if (pDiskInfo[i].Capacity > 0 && i != g_vtoy_disk_drive)\r
+            {\r
+                Log("%s=<PhyDrive%d>", var, i);\r
+                sprintf_s(value, len, "%d", i);\r
+                return 0;\r
+            }\r
+        }\r
+    }\r
+    else if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONUSB") == 0)\r
+    {\r
+        for (i = 0; i < DiskNum; i++)\r
+        {\r
+            if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].BusType != BusTypeUsb)\r
+            {\r
+                Log("%s=<PhyDrive%d>", var, i);\r
+                sprintf_s(value, len, "%d", i);\r
+                return 0;\r
+            }\r
+        }\r
+    }\r
+    else if (strcmp(var, "VT_WINDOWS_DISK_MAX_SIZE") == 0)\r
+    {\r
+        for (i = 0; i < DiskNum; i++)\r
+        {\r
+            if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].Capacity > uiMaxSize)\r
+            {\r
+                index = i;\r
+                uiMaxSize = pDiskInfo[i].Capacity;\r
+            }\r
+        }\r
+\r
+        Log("%s=<PhyDrive%d>", var, index);\r
+        sprintf_s(value, len, "%d", index);\r
+    }\r
+    else if (strncmp(var, "VT_WINDOWS_DISK_CLOSEST_", 24) == 0)\r
+    {\r
+        uiDst = strtoul(var + 24, NULL, 10);\r
+        uiDst = uiDst * (1024ULL * 1024ULL * 1024ULL);\r
+    \r
+        for (i = 0; i < DiskNum; i++)\r
+        {\r
+            if (pDiskInfo[i].Capacity == 0)\r
+            {\r
+                continue;\r
+            }\r
+        \r
+            if (pDiskInfo[i].Capacity > uiDst)\r
+            {\r
+                uiDelta = pDiskInfo[i].Capacity - uiDst;\r
+            }\r
+            else\r
+            {\r
+                uiDelta = uiDst - pDiskInfo[i].Capacity;\r
+            }\r
+            \r
+            if (uiDelta < uiMaxDelta)\r
+            {\r
+                uiMaxDelta = uiDelta;\r
+                index = i;\r
+            }\r
+        }\r
+\r
+        Log("%s=<PhyDrive%d>", var, index);\r
+        sprintf_s(value, len, "%d", index);\r
+    }\r
+    else\r
+    {\r
+        Log("Invalid var name <%s>", var);\r
+        sprintf_s(value, len, "$$%s$$", var);\r
+    }\r
+    \r
+    if (value[0] == 0)\r
+    {\r
+        sprintf_s(value, len, "$$%s$$", var);\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)\r
+{\r
+    HKEY hKey;\r
+    DWORD Type;\r
+    DWORD Size;\r
+    LSTATUS lRet;\r
+    DWORD Value;\r
+\r
+    lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);\r
+    Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);\r
+\r
+    if (ERROR_SUCCESS == lRet)\r
+    {\r
+        Size = sizeof(Value);\r
+        lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);\r
+        Log("RegQueryValueExA <%s> ret:%u  Size:%u Value:%u", ValueName, lRet, Size, Value);\r
+\r
+        *pValue = Value;\r
+        RegCloseKey(hKey);\r
+\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        return 1;\r
+    }\r
+}\r
+\r
+static const CHAR * GetBusTypeString(int Type)\r
+{\r
+    switch (Type)\r
+    {\r
+        case BusTypeUnknown: return "unknown";\r
+        case BusTypeScsi: return "SCSI";\r
+        case BusTypeAtapi: return "Atapi";\r
+        case BusTypeAta: return "ATA";\r
+        case BusType1394: return "1394";\r
+        case BusTypeSsa: return "SSA";\r
+        case BusTypeFibre: return "Fibre";\r
+        case BusTypeUsb: return "USB";\r
+        case BusTypeRAID: return "RAID";\r
+        case BusTypeiScsi: return "iSCSI";\r
+        case BusTypeSas: return "SAS";\r
+        case BusTypeSata: return "SATA";\r
+        case BusTypeSd: return "SD";\r
+        case BusTypeMmc: return "MMC";\r
+        case BusTypeVirtual: return "Virtual";\r
+        case BusTypeFileBackedVirtual: return "FileBackedVirtual";\r
+        case BusTypeSpaces: return "Spaces";\r
+        case BusTypeNvme: return "Nvme";\r
+    }\r
+    return "unknown";\r
+}\r
+\r
+static int GetHumanReadableGBSize(UINT64 SizeBytes)\r
+{\r
+    int i;\r
+    int Pow2 = 1;\r
+    double Delta;\r
+    double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;\r
+\r
+    if ((SizeBytes % 1073741824) == 0)\r
+    {\r
+        return (int)(SizeBytes / 1073741824);\r
+    }\r
+\r
+    for (i = 0; i < 12; i++)\r
+    {\r
+        if (Pow2 > GB)\r
+        {\r
+            Delta = (Pow2 - GB) / Pow2;\r
+        }\r
+        else\r
+        {\r
+            Delta = (GB - Pow2) / Pow2;\r
+        }\r
+\r
+        if (Delta < 0.05)\r
+        {\r
+            return Pow2;\r
+        }\r
+\r
+        Pow2 <<= 1;\r
+    }\r
+\r
+    return (int)GB;\r
+}\r
+\r
+static int EnumerateAllDisk(VarDiskInfo **ppDiskInfo, int *pDiskNum)\r
+{\r
+    int i;\r
+    DWORD Value;\r
+    int DiskNum = 0;\r
+    BOOL  bRet;\r
+    DWORD dwBytes;\r
+    VarDiskInfo *pDiskInfo = NULL;\r
+    HANDLE Handle = INVALID_HANDLE_VALUE;\r
+    CHAR PhyDrive[128];    \r
+    GET_LENGTH_INFORMATION LengthInfo;\r
+    STORAGE_PROPERTY_QUERY Query;\r
+    STORAGE_DESCRIPTOR_HEADER DevDescHeader;\r
+    STORAGE_DEVICE_DESCRIPTOR *pDevDesc;\r
+    \r
+    if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)\r
+    {\r
+        DiskNum = (int)Value;\r
+    }\r
+    else\r
+    {\r
+        Log("Failed to read disk count");\r
+        return 1;\r
+    }\r
+\r
+    Log("Current phy disk count:%d", DiskNum);\r
+    if (DiskNum <= 0)\r
+    {\r
+        return 1;\r
+    }\r
+\r
+    pDiskInfo = malloc(DiskNum * sizeof(VarDiskInfo));\r
+    if (!pDiskInfo)\r
+    {\r
+        Log("Failed to alloc");\r
+        return 1;\r
+    }\r
+    memset(pDiskInfo, 0, DiskNum * sizeof(VarDiskInfo));\r
+\r
+    for (i = 0; i < DiskNum; i++)\r
+    {\r
+        SAFE_CLOSE_HANDLE(Handle);\r
+\r
+        safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", i);\r
+        Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);        \r
+        Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);\r
+\r
+        if (Handle == INVALID_HANDLE_VALUE)\r
+        {\r
+            continue;\r
+        }\r
+\r
+        bRet = DeviceIoControl(Handle,\r
+                               IOCTL_DISK_GET_LENGTH_INFO, NULL,\r
+                               0,\r
+                               &LengthInfo,\r
+                               sizeof(LengthInfo),\r
+                               &dwBytes,\r
+                               NULL);\r
+        if (!bRet)\r
+        {\r
+            Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);\r
+            continue;\r
+        }\r
+\r
+        Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);\r
+\r
+        Query.PropertyId = StorageDeviceProperty;\r
+        Query.QueryType = PropertyStandardQuery;\r
+\r
+        bRet = DeviceIoControl(Handle,\r
+                               IOCTL_STORAGE_QUERY_PROPERTY,\r
+                               &Query,\r
+                               sizeof(Query),\r
+                               &DevDescHeader,\r
+                               sizeof(STORAGE_DESCRIPTOR_HEADER),\r
+                               &dwBytes,\r
+                               NULL);\r
+        if (!bRet)\r
+        {\r
+            Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);\r
+            continue;\r
+        }\r
+\r
+        if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))\r
+        {\r
+            Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);\r
+            continue;\r
+        }\r
+\r
+        pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);\r
+        if (!pDevDesc)\r
+        {\r
+            Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);\r
+            continue;\r
+        }\r
+\r
+        bRet = DeviceIoControl(Handle,\r
+                               IOCTL_STORAGE_QUERY_PROPERTY,\r
+                               &Query,\r
+                               sizeof(Query),\r
+                               pDevDesc,\r
+                               DevDescHeader.Size,\r
+                               &dwBytes,\r
+                               NULL);\r
+        if (!bRet)\r
+        {\r
+            Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);\r
+            free(pDevDesc);\r
+            continue;\r
+        }\r
+\r
+        pDiskInfo[i].RemovableMedia = pDevDesc->RemovableMedia;\r
+        pDiskInfo[i].BusType = pDevDesc->BusType;\r
+        pDiskInfo[i].DeviceType = pDevDesc->DeviceType;\r
+        pDiskInfo[i].Capacity = LengthInfo.Length.QuadPart;\r
+\r
+        if (pDevDesc->VendorIdOffset)\r
+        {\r
+            safe_strcpy(pDiskInfo[i].VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);\r
+            TrimString(pDiskInfo[i].VendorId, TRUE);\r
+        }\r
+\r
+        if (pDevDesc->ProductIdOffset)\r
+        {\r
+            safe_strcpy(pDiskInfo[i].ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);\r
+            TrimString(pDiskInfo[i].ProductId, TRUE);\r
+        }\r
+\r
+        if (pDevDesc->ProductRevisionOffset)\r
+        {\r
+            safe_strcpy(pDiskInfo[i].ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);\r
+            TrimString(pDiskInfo[i].ProductRev, TRUE);\r
+        }\r
+\r
+        if (pDevDesc->SerialNumberOffset)\r
+        {\r
+            safe_strcpy(pDiskInfo[i].SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);\r
+            TrimString(pDiskInfo[i].SerialNumber, TRUE);\r
+        }\r
+\r
+        free(pDevDesc);\r
+        SAFE_CLOSE_HANDLE(Handle);\r
+    }\r
+\r
+    Log("########## DUMP DISK BEGIN ##########");\r
+    for (i = 0; i < DiskNum; i++)\r
+    {\r
+        Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",\r
+            i, GetBusTypeString(pDiskInfo[i].BusType), pDiskInfo[i].RemovableMedia,\r
+            GetHumanReadableGBSize(pDiskInfo[i].Capacity), pDiskInfo[i].Capacity,\r
+            pDiskInfo[i].VendorId, pDiskInfo[i].ProductId);\r
+    }\r
+    Log("Ventoy disk is PhyDvr%d", g_vtoy_disk_drive);\r
+    Log("########## DUMP DISK END ##########");\r
+\r
+    *ppDiskInfo = pDiskInfo;\r
+    *pDiskNum = DiskNum;\r
+    return 0;\r
+}\r
+\r
+static int UnattendVarExpand(const char *script, const char *tmpfile)\r
+{\r
+    FILE *fp = NULL;\r
+    FILE *fout = NULL;\r
+    char *start = NULL;\r
+    char *end = NULL;\r
+    char szLine[4096];\r
+    char szValue[256];\r
+    int DiskNum = 0;\r
+    VarDiskInfo *pDiskInfo = NULL;\r
+\r
+    Log("UnattendVarExpand ...");\r
+\r
+    if (EnumerateAllDisk(&pDiskInfo, &DiskNum))\r
+    {\r
+        Log("Failed to EnumerateAllDisk");\r
+        return 1;\r
+    }\r
+    \r
+    fopen_s(&fp, script, "r");\r
+    if (!fp)\r
+    {\r
+        free(pDiskInfo);\r
+        return 0;\r
+    }\r
+\r
+    fopen_s(&fout, tmpfile, "w+");\r
+    if (!fout)\r
+    {\r
+        fclose(fp);\r
+        free(pDiskInfo);\r
+        return 0;\r
+    }\r
+\r
+    szLine[0] = szLine[4095] = 0;\r
+    \r
+    while (fgets(szLine, sizeof(szLine) - 1, fp))\r
+    {\r
+        start = strstr(szLine, "$$VT_");\r
+        if (start)\r
+        {\r
+            end = strstr(start + 5, "$$");\r
+        }\r
+\r
+        if (start && end)\r
+        {\r
+            *start = 0;\r
+            fprintf(fout, "%s", szLine);\r
+\r
+            *end = 0;\r
+            ExpandSingleVar(pDiskInfo, DiskNum, start + 2, szValue, sizeof(szValue) - 1);\r
+            fprintf(fout, "%s", szValue);\r
+            \r
+            fprintf(fout, "%s", end + 2);\r
+        }\r
+        else\r
+        {\r
+            fprintf(fout, "%s", szLine);\r
+        }\r
+        \r
+        szLine[0] = szLine[4095] = 0;\r
+    }\r
+\r
+    fclose(fp);\r
+    fclose(fout);\r
+    free(pDiskInfo);\r
+    return 0;\r
+}\r
+\r
+//#define VAR_DEBUG 1\r
+\r
+static int CreateUnattendRegKey(const char *file)\r
+{\r
+    DWORD dw;\r
+    HKEY hKey;\r
+    LSTATUS Ret;\r
+\r
+#ifndef VAR_DEBUG\r
+    Ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw);\r
+    if (ERROR_SUCCESS == Ret)\r
+    {\r
+        Ret = RegSetValueEx(hKey, "UnattendFile", 0, REG_SZ, file, (DWORD)(strlen(file) + 1));\r
+    }\r
+#endif\r
+\r
+    return 0;\r
+}\r
+\r
+static int ProcessUnattendedInstallation(const char *script, DWORD PhyDrive)\r
+{\r
+    CHAR Letter;\r
+    CHAR DrvLetter;\r
+    CHAR TmpFile[MAX_PATH];\r
+    CHAR CurDir[MAX_PATH];\r
+    CHAR ImPath[MAX_PATH];\r
+\r
+    Log("Copy unattended XML ...");\r
+    \r
+    GetCurrentDirectory(sizeof(CurDir), CurDir);\r
+    Letter = CurDir[0];\r
+    if ((Letter >= 'A' && Letter <= 'Z') || (Letter >= 'a' && Letter <= 'z'))\r
+    {\r
+        Log("Current Drive Letter: %C", Letter);\r
+    }\r
+    else\r
+    {\r
+        Letter = 'X';\r
+    }\r
+\r
+#ifdef VAR_DEBUG\r
+    sprintf_s(CurDir, sizeof(CurDir), "%C:\\AutounattendXXX.xml", Letter);\r
+#else\r
+    sprintf_s(CurDir, sizeof(CurDir), "%C:\\Unattend.xml", Letter);\r
+#endif\r
+\r
+    if (UnattendNeedVarExpand(script))\r
+    {\r
+        sprintf_s(TmpFile, sizeof(TmpFile), "%C:\\__Autounattend", Letter);\r
+        UnattendVarExpand(script, TmpFile);\r
+        \r
+        Log("Expand Copy file <%s> --> <%s>", script, CurDir);\r
+        CopyFileA(TmpFile, CurDir, FALSE);\r
+    }\r
+    else\r
+    {\r
+        Log("No var expand copy file <%s> --> <%s>", script, CurDir);\r
+        CopyFileA(script, CurDir, FALSE);\r
+    }\r
+\r
+    VentoyCopyImdisk(PhyDrive, ImPath);\r
+    DrvLetter = VentoyGetFirstFreeDriveLetter(FALSE);\r
+    VentoyProcessRunCmd("%s -a -s 64M -m %C: -p \"/fs:FAT32 /q /y\"", ImPath, DrvLetter);\r
+\r
+    Sleep(300);\r
+\r
+    sprintf_s(TmpFile, sizeof(TmpFile), "%C:\\Unattend.xml", DrvLetter);\r
+    if (CopyFileA(CurDir, TmpFile, FALSE))\r
+    {\r
+        DeleteFileA(CurDir);\r
+        Log("Move file <%s> ==> <%s>, use the later as unattend XML", CurDir, TmpFile);\r
+        CreateUnattendRegKey(TmpFile);\r
+    }\r
+    else\r
+    {\r
+        Log("Failed to copy file <%s> ==> <%s>, use OLD", CurDir, TmpFile);\r
+        CreateUnattendRegKey(CurDir);\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static int Windows11Bypass(const char *isofile, const char MntLetter, UINT8 Check, UINT8 NRO)\r
+{\r
+    int Ret = 1;\r
+    DWORD dwHandle;\r
+    DWORD dwSize;\r
+    DWORD dwValue = 1;\r
+    UINT VerLen = 0;\r
+    CHAR *Buffer = NULL;\r
+    VS_FIXEDFILEINFO* VerInfo = NULL;\r
+    CHAR CheckFile[MAX_PATH];\r
+    UINT16 Major, Minor, Build, Revision;\r
+\r
+    Log("Windows11Bypass for <%s> %C: Check:%u NRO:%u", isofile, MntLetter, Check, NRO);\r
+\r
+    if (FALSE == IsFileExist("%C:\\sources\\boot.wim", MntLetter) ||\r
+        FALSE == IsFileExist("%C:\\sources\\compatresources.dll", MntLetter))\r
+    {\r
+        Log("boot.wim/compatresources.dll not exist, this is not a windows install media.");\r
+        goto End;\r
+    }\r
+\r
+    if (FALSE == IsFileExist("%C:\\sources\\install.wim", MntLetter) && \r
+        FALSE == IsFileExist("%C:\\sources\\install.esd", MntLetter))\r
+    {\r
+        Log("install.wim/install.esd not exist, this is not a windows install media.");\r
+        goto End;\r
+    }\r
+\r
+    sprintf_s(CheckFile, sizeof(CheckFile), "%C:\\sources\\compatresources.dll", MntLetter);\r
+    dwSize = GetFileVersionInfoSizeA(CheckFile, &dwHandle);\r
+    if (0 == dwSize)\r
+    {\r
+        Log("Failed to get file version info size: %u", LASTERR);\r
+        goto End;\r
+    }\r
+\r
+    Buffer = malloc(dwSize);\r
+    if (!Buffer)\r
+    {\r
+        goto End;\r
+    }\r
+\r
+    if (FALSE == GetFileVersionInfoA(CheckFile, dwHandle, dwSize, Buffer))\r
+    {\r
+        Log("Failed to get file version info : %u", LASTERR);\r
+        goto End;\r
+    }\r
+\r
+    if (VerQueryValueA(Buffer, "\\", (LPVOID)&VerInfo, &VerLen) && VerLen != 0)\r
+    {\r
+        if (VerInfo->dwSignature == VS_FFI_SIGNATURE)\r
+        {\r
+            Major = HIWORD(VerInfo->dwFileVersionMS);\r
+            Minor = LOWORD(VerInfo->dwFileVersionMS);\r
+            Build = HIWORD(VerInfo->dwFileVersionLS);\r
+            Revision = LOWORD(VerInfo->dwFileVersionLS);\r
+\r
+            Log("FileVersionze: <%u %u %u %u>", Major, Minor, Build, Revision);\r
+\r
+            if (Major == 10 && Build > 20000)\r
+            {\r
+                Major = 11;\r
+            }\r
+\r
+            if (Major != 11)\r
+            {\r
+                Log("This is not Windows 11, not need to bypass.", Major);\r
+                goto End;\r
+            }\r
+        }\r
+    }\r
+\r
+    //Now we really need to bypass windows 11 check. create registry\r
+    HKEY hKey = NULL;\r
+    HKEY hSubKey = NULL;\r
+    LSTATUS Status;\r
+\r
+    if (Check)\r
+    {\r
+        Status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize);\r
+        if (ERROR_SUCCESS != Status)\r
+        {\r
+            Log("Failed to create reg key System\\Setup %u %u", LASTERR, Status);\r
+            goto End;\r
+        }\r
+\r
+        Status = RegCreateKeyExA(hKey, "LabConfig", 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hSubKey, &dwSize);\r
+        if (ERROR_SUCCESS != Status)\r
+        {\r
+            Log("Failed to create LabConfig reg  %u %u", LASTERR, Status);\r
+            goto End;\r
+        }\r
+\r
+        //set reg value\r
+        Status += RegSetValueExA(hSubKey, "BypassRAMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));\r
+        Status += RegSetValueExA(hSubKey, "BypassTPMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));\r
+        Status += RegSetValueExA(hSubKey, "BypassSecureBootCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));\r
+        Status += RegSetValueExA(hSubKey, "BypassCPUCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));\r
+\r
+        Log("Create bypass check registry %s %u", (Status == ERROR_SUCCESS) ? "SUCCESS" : "FAILED", Status);\r
+    }\r
+\r
+\r
+    if (NRO)\r
+    {\r
+        Status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize);\r
+        if (ERROR_SUCCESS != Status)\r
+        {\r
+            Log("Failed to create reg key SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE %u %u", LASTERR, Status);\r
+            goto End;\r
+        }\r
+\r
+        Status = RegCreateKeyExA(hKey, "OOBE", 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hSubKey, &dwSize);\r
+        if (ERROR_SUCCESS != Status)\r
+        {\r
+            Log("Failed to create OOBE reg  %u %u", LASTERR, Status);\r
+            goto End;\r
+        }\r
+\r
+        Status += RegSetValueExA(hSubKey, "BypassNRO", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));\r
+        Log("Create BypassNRO registry %s %u", (Status == ERROR_SUCCESS) ? "SUCCESS" : "FAILED", Status);\r
+    }\r
+    \r
+\r
+    Ret = 0;\r
+\r
+End:\r
+    if (Buffer)\r
+    {\r
+        free(Buffer);\r
+    }\r
+    \r
+    return Ret; \r
+}\r
+\r
+static BOOL CheckVentoyDisk(DWORD DiskNum)\r
+{\r
+    DWORD dwSize = 0;\r
+    CHAR PhyPath[128];\r
+    UINT8 SectorBuf[512];\r
+    HANDLE Handle;\r
+    UINT8 check[8] = { 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44 };\r
+\r
+    sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskNum);\r
+    Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+    if (Handle == INVALID_HANDLE_VALUE)\r
+    {\r
+        Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());\r
+        return FALSE;\r
+    }\r
+\r
+    if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))\r
+    {\r
+        Log("ReadFile failed, dwSize:%u  error:%u", dwSize, GetLastError());\r
+        CloseHandle(Handle);\r
+        return FALSE;\r
+    }\r
+\r
+    CloseHandle(Handle);\r
+\r
+    if (memcmp(SectorBuf + 0x190, check, 8) == 0)\r
+    {\r
+        return TRUE;\r
+    }\r
+\r
+    return FALSE;\r
+}\r
+\r
+\r
+static int VentoyHook(ventoy_os_param *param)\r
+{\r
+    int i;\r
+    int rc;\r
+    BOOL find = FALSE;\r
+    BOOL vtoyfind = FALSE;\r
+    CHAR Letter;\r
+    CHAR MntLetter;\r
+    CHAR VtoyLetter;\r
+    DWORD Drives;\r
+    DWORD NewDrives;\r
+    DWORD VtoyDiskNum;\r
+    UINT32 DiskSig;\r
+    UINT32 VtoySig;\r
+    DISK_EXTENT DiskExtent;\r
+    DISK_EXTENT VtoyDiskExtent;\r
+    UINT8 UUID[16];\r
+    CHAR IsoPath[MAX_PATH];\r
+\r
+    Log("VentoyHook Path:<%s>", param->vtoy_img_path);\r
+\r
+    if (IsUTF8Encode(param->vtoy_img_path))\r
+    {\r
+        Log("This file is UTF8 encoding");\r
+    }\r
+\r
+    for (i = 0; i < 5; i++)\r
+    {\r
+        Letter = 'A';\r
+        Drives = GetLogicalDrives();\r
+        Log("Logic Drives: 0x%x", Drives);\r
+\r
+        while (Drives)\r
+        {\r
+            if (Drives & 0x01)\r
+            {\r
+                sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);\r
+                if (IsFileExist("%s", IsoPath))\r
+                {\r
+                    Log("File exist under %C:", Letter);\r
+                    memset(UUID, 0, sizeof(UUID));\r
+                    memset(&DiskExtent, 0, sizeof(DiskExtent));\r
+                    if (GetPhyDiskUUID(Letter, UUID, NULL, &DiskExtent) == 0)\r
+                    {\r
+                        if (memcmp(UUID, param->vtoy_disk_guid, 16) == 0)\r
+                        {\r
+                            Log("Disk UUID match");\r
+                            find = TRUE;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    Log("File NOT exist under %C:", Letter);\r
+                }\r
+            }\r
+\r
+            Drives >>= 1;\r
+            Letter++;\r
+        }\r
+\r
+        if (find)\r
+        {\r
+            break;\r
+        }\r
+        else\r
+        {\r
+            Log("Now wait and retry ...");\r
+            Sleep(1000);\r
+        }\r
+    }\r
+\r
+    if (find == FALSE)\r
+    {\r
+        Log("Failed to find ISO file");\r
+        return 1;\r
+    }\r
+\r
+    Log("Find ISO file <%s>", IsoPath);\r
+    \r
+    //Find VtoyLetter in Vlnk Mode\r
+    if (g_os_param_reserved[6] == 1)\r
+    {\r
+        memcpy(&VtoySig, g_os_param_reserved + 7, 4);\r
+        for (i = 0; i < 5; i++)\r
+        {\r
+            VtoyLetter = 'A';\r
+            Drives = GetLogicalDrives();\r
+            Log("Logic Drives: 0x%x  VentoySig:%08X", Drives, VtoySig);\r
+\r
+            while (Drives)\r
+            {\r
+                if (Drives & 0x01)\r
+                {\r
+                    memset(UUID, 0, sizeof(UUID));\r
+                    memset(&VtoyDiskExtent, 0, sizeof(VtoyDiskExtent));\r
+                    DiskSig = 0;\r
+                    if (GetPhyDiskUUID(VtoyLetter, UUID, &DiskSig, &VtoyDiskExtent) == 0)\r
+                    {\r
+                        Log("DiskSig=%08X PartStart=%lld", DiskSig, VtoyDiskExtent.StartingOffset.QuadPart);\r
+                        if (DiskSig == VtoySig && VtoyDiskExtent.StartingOffset.QuadPart == SIZE_1MB)\r
+                        {\r
+                            Log("Ventoy Disk Sig match");\r
+                            vtoyfind = TRUE;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+\r
+                Drives >>= 1;\r
+                VtoyLetter++;\r
+            }\r
+\r
+            if (vtoyfind)\r
+            {\r
+                Log("Find Ventoy Letter: %C", VtoyLetter);\r
+                break;\r
+            }\r
+            else\r
+            {\r
+                Log("Now wait and retry ...");\r
+                Sleep(1000);\r
+            }\r
+        }\r
+\r
+        if (vtoyfind == FALSE)\r
+        {\r
+            Log("Failed to find ventoy disk");\r
+            return 1;\r
+        }\r
+\r
+        VtoyDiskNum = VtoyDiskExtent.DiskNumber;\r
+    }\r
+    else\r
+    {\r
+        VtoyLetter = Letter;\r
+        Log("No vlnk mode %C", Letter);\r
+\r
+        VtoyDiskNum = DiskExtent.DiskNumber;\r
+    }\r
+\r
+    if (CheckVentoyDisk(VtoyDiskNum))\r
+    {\r
+        Log("Disk check OK %C: %u", VtoyLetter, VtoyDiskNum);\r
+    }\r
+    else\r
+    {\r
+        Log("Failed to check ventoy disk %u", VtoyDiskNum);\r
+        return 1;\r
     }\r
 \r
-       while (Drives)\r
-       {\r
-        if (Drives & 0x01)\r
+    g_vtoy_disk_drive = VtoyDiskNum;\r
+\r
+    Drives = GetLogicalDrives();\r
+    Log("Drives before mount: 0x%x", Drives);\r
+\r
+    rc = MountIsoFile(IsoPath, VtoyDiskNum);\r
+\r
+    NewDrives = GetLogicalDrives();\r
+    Log("Drives after mount: 0x%x (0x%x)", NewDrives, (NewDrives ^ Drives));\r
+\r
+    MntLetter = 'A';\r
+    NewDrives = (NewDrives ^ Drives);\r
+    while (NewDrives)\r
+    {\r
+        if (NewDrives & 0x01)\r
         {\r
-            sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);\r
-            if (IsFileExist("%s", IsoPath))\r
+            if ((NewDrives >> 1) == 0)\r
             {\r
-                Log("File exist under %C:", Letter);\r
-                if (GetPhyDiskUUID(Letter, UUID, &DiskExtent) == 0)\r
-                {\r
-                    if (memcmp(UUID, param->vtoy_disk_guid, 16) == 0)\r
-                    {\r
-                        Log("Disk UUID match");\r
-                        break;\r
-                    }\r
-                }\r
+                Log("The ISO file is mounted at %C:", MntLetter);\r
             }\r
             else\r
             {\r
-                Log("File NOT exist under %C:", Letter);\r
+                Log("Maybe the ISO file is mounted at %C:", MntLetter);\r
             }\r
+            break;\r
         }\r
 \r
-               Drives >>= 1;\r
-               Letter++;\r
-       }\r
-\r
-       if (Drives == 0)\r
-       {\r
-               Log("Failed to find ISO file");\r
-               return 1;\r
-       }\r
+        NewDrives >>= 1;\r
+        MntLetter++;\r
+    }\r
 \r
-       Log("Find ISO file <%s>", IsoPath);\r
-    \r
-    rc = MountIsoFile(IsoPath, DiskExtent.DiskNumber);\r
     Log("Mount ISO FILE: %s", rc == 0 ? "SUCCESS" : "FAILED");\r
 \r
+    //Windows 11 bypass check\r
+    if (g_windows_data.windows11_bypass_check == 1 || g_windows_data.windows11_bypass_nro == 1)\r
+    {\r
+        Windows11Bypass(IsoPath, MntLetter, g_windows_data.windows11_bypass_check, g_windows_data.windows11_bypass_nro);\r
+    }\r
+\r
     // for protect\r
-    rc = DeleteVentoyPart2MountPoint(DiskExtent.DiskNumber);\r
+    rc = DeleteVentoyPart2MountPoint(VtoyDiskNum);\r
     Log("Delete ventoy mountpoint: %s", rc == 0 ? "SUCCESS" : "NO NEED");\r
     \r
     if (g_windows_data.auto_install_script[0])\r
     {\r
-        sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", Letter, g_windows_data.auto_install_script);\r
-        if (IsFileExist("%s", IsoPath))\r
+        if (IsFileExist("%s", VTOY_AUTO_FILE))\r
         {\r
-            Log("use auto install script %s...", IsoPath);\r
-            ProcessUnattendedInstallation(IsoPath);\r
+            Log("use auto install script %s...", VTOY_AUTO_FILE);\r
+            ProcessUnattendedInstallation(VTOY_AUTO_FILE, VtoyDiskNum);\r
         }\r
         else\r
         {\r
@@ -1227,11 +2405,51 @@ static int VentoyHook(ventoy_os_param *param)
 \r
     if (g_windows_data.injection_archive[0])\r
     {\r
-        sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", Letter, g_windows_data.injection_archive);\r
+        sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", VtoyLetter, g_windows_data.injection_archive);\r
         if (IsFileExist("%s", IsoPath))\r
         {\r
             Log("decompress injection archive %s...", IsoPath);\r
-            DecompressInjectionArchive(IsoPath, DiskExtent.DiskNumber);\r
+            DecompressInjectionArchive(IsoPath, VtoyDiskNum);\r
+\r
+            if (IsFileExist("%s", AUTO_RUN_BAT))\r
+            {\r
+                HANDLE hOut;\r
+                DWORD flags = CREATE_NO_WINDOW;\r
+                CHAR StrBuf[1024];\r
+                STARTUPINFOA Si;\r
+                PROCESS_INFORMATION Pi;\r
+                SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };\r
+\r
+                Log("%s exist, now run it...", AUTO_RUN_BAT);\r
+\r
+                GetStartupInfoA(&Si);\r
+\r
+                hOut = CreateFileA(AUTO_RUN_LOG,\r
+                    FILE_APPEND_DATA,\r
+                    FILE_SHARE_WRITE | FILE_SHARE_READ,\r
+                    &Sa,\r
+                    OPEN_ALWAYS,\r
+                    FILE_ATTRIBUTE_NORMAL,\r
+                    NULL);\r
+\r
+                Si.dwFlags |= STARTF_USESTDHANDLES;\r
+                if (hOut != INVALID_HANDLE_VALUE)\r
+                {\r
+                    Si.hStdError = hOut;\r
+                    Si.hStdOutput = hOut;\r
+                }\r
+\r
+                sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);\r
+                sprintf_s(StrBuf, sizeof(StrBuf), "cmd.exe /c %s \"%s\" %C", AUTO_RUN_BAT, IsoPath, MntLetter);\r
+                CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);\r
+                WaitForSingleObject(Pi.hProcess, INFINITE);\r
+\r
+                SAFE_CLOSE_HANDLE(hOut);\r
+            }\r
+            else\r
+            {\r
+                Log("%s not exist...", AUTO_RUN_BAT);\r
+            }\r
         }\r
         else\r
         {\r
@@ -1246,81 +2464,24 @@ static int VentoyHook(ventoy_os_param *param)
     return 0;\r
 }\r
 \r
-const char * GetFileNameInPath(const char *fullpath)\r
-{\r
-       int i;\r
-       const char *pos = NULL;\r
-\r
-       if (strstr(fullpath, ":"))\r
-       {\r
-               for (i = (int)strlen(fullpath); i > 0; i--)\r
-               {\r
-                       if (fullpath[i - 1] == '/' || fullpath[i - 1] == '\\')\r
-                       {\r
-                               return fullpath + i;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       return fullpath;\r
-}\r
-\r
-int VentoyJumpWimboot(INT argc, CHAR **argv, CHAR *LunchFile)\r
+static int ExtractWindowsDataFile(char *databuf)\r
 {\r
-    int rc = 1;\r
-    char *buf = NULL;\r
-    DWORD size = 0;\r
-    DWORD Pos;\r
-\r
-#ifdef VTOY_32\r
-    g_64bit_system = FALSE;\r
-#else\r
-    g_64bit_system = TRUE;\r
-#endif\r
-    \r
-    Log("VentoyJumpWimboot %dbit", g_64bit_system ? 64 : 32);\r
-\r
-    sprintf_s(LunchFile, MAX_PATH, "X:\\setup.exe");\r
-\r
-    ReadWholeFile2Buf("wimboot.data", &buf, &size);\r
-    Log("wimboot.data size:%d", size);\r
-\r
-    memcpy(&g_os_param, buf, sizeof(ventoy_os_param));\r
-    memcpy(&g_windows_data, buf + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));\r
-    memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));\r
-\r
-    if (g_os_param_reserved[0] == 1)\r
-    {\r
-        Log("break here for debug .....");\r
-        goto End;\r
-    }\r
-\r
-    // convert / to \\   \r
-    for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)\r
-    {\r
-        if (g_os_param.vtoy_img_path[Pos] == '/')\r
-        {\r
-            g_os_param.vtoy_img_path[Pos] = '\\';\r
-        }\r
-    }\r
-\r
-    if (g_os_param_reserved[0] == 2)\r
-    {\r
-        Log("skip hook for debug .....");\r
-        rc = 0;\r
-        goto End;\r
-    }\r
+    int len = 0;\r
+    char *filedata = NULL;\r
+    ventoy_windows_data *pdata = (ventoy_windows_data *)databuf;\r
 \r
-    rc = VentoyHook(&g_os_param);\r
+    Log("ExtractWindowsDataFile: auto install <%s:%d>", pdata->auto_install_script, pdata->auto_install_len);\r
 \r
-End:\r
+    filedata = databuf + sizeof(ventoy_windows_data);\r
 \r
-    if (buf)\r
+    if (pdata->auto_install_script[0] && pdata->auto_install_len > 0)\r
     {\r
-        free(buf);\r
+        SaveBuffer2File(VTOY_AUTO_FILE, filedata, pdata->auto_install_len);\r
+        filedata += pdata->auto_install_len;\r
+        len = pdata->auto_install_len;\r
     }\r
-\r
-    return rc;\r
+    \r
+    return len;\r
 }\r
 \r
 static int ventoy_check_create_directory(void)\r
@@ -1344,31 +2505,31 @@ static int ventoy_check_create_directory(void)
 \r
 int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)\r
 {\r
-       int rc = 1;\r
+    int rc = 1;\r
     int stat = 0;\r
-       DWORD Pos;\r
-       DWORD PeStart;\r
+    int exlen = 0;\r
+    DWORD Pos;\r
+    DWORD PeStart;\r
     DWORD FileSize;\r
     DWORD LockStatus = 0;\r
-       BYTE *Buffer = NULL; \r
-       CHAR ExeFileName[MAX_PATH];\r
-\r
-       sprintf_s(ExeFileName, sizeof(ExeFileName), "%s", argv[0]);\r
-       if (!IsFileExist("%s", ExeFileName))\r
-       {\r
-               Log("File %s NOT exist, now try %s.exe", ExeFileName, ExeFileName);\r
-               sprintf_s(ExeFileName, sizeof(ExeFileName), "%s.exe", argv[0]);\r
-\r
-               Log("File %s exist ? %s", ExeFileName, IsFileExist("%s", ExeFileName) ? "YES" : "NO");\r
-       }\r
-\r
-       if (ReadWholeFile2Buf(ExeFileName, (void **)&Buffer, &FileSize))\r
-       {\r
-               goto End;\r
-       }\r
-       \r
-       g_64bit_system = IsPe64(Buffer);\r
-    Log("VentoyJump %dbit", g_64bit_system ? 64 : 32);\r
+    BYTE *Buffer = NULL; \r
+    CHAR ExeFileName[MAX_PATH];\r
+\r
+    sprintf_s(ExeFileName, sizeof(ExeFileName), "%s", argv[0]);\r
+    if (!IsFileExist("%s", ExeFileName))\r
+    {\r
+        Log("File %s NOT exist, now try %s.exe", ExeFileName, ExeFileName);\r
+        sprintf_s(ExeFileName, sizeof(ExeFileName), "%s.exe", argv[0]);\r
+\r
+        Log("File %s exist ? %s", ExeFileName, IsFileExist("%s", ExeFileName) ? "YES" : "NO");\r
+    }\r
+\r
+    if (ReadWholeFile2Buf(ExeFileName, (void **)&Buffer, &FileSize))\r
+    {\r
+        goto End;\r
+    }\r
+    \r
+    Log("VentoyJump %dbit", g_system_bit);\r
 \r
     MUTEX_LOCK(g_vtoyins_mutex);\r
     stat = ventoy_check_create_directory();\r
@@ -1379,34 +2540,35 @@ int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
         goto End;\r
     }\r
 \r
-       for (PeStart = 0; PeStart < FileSize; PeStart += 16)\r
-       {\r
-               if (CheckOsParam((ventoy_os_param *)(Buffer + PeStart)) && \r
-            CheckPeHead(Buffer + PeStart + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data)))\r
-               {\r
-                       Log("Find os pararm at %u", PeStart);\r
+    for (PeStart = 0; PeStart < FileSize; PeStart += 16)\r
+    {\r
+        if (CheckOsParam((ventoy_os_param *)(Buffer + PeStart)) && \r
+            CheckPeHead(Buffer, FileSize, PeStart + sizeof(ventoy_os_param)))\r
+        {\r
+            Log("Find os pararm at %u", PeStart);\r
 \r
             memcpy(&g_os_param, Buffer + PeStart, sizeof(ventoy_os_param));\r
-            memcpy(&g_windows_data, Buffer + PeStart + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));            \r
+            memcpy(&g_windows_data, Buffer + PeStart + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));  \r
+            exlen = ExtractWindowsDataFile(Buffer + PeStart + sizeof(ventoy_os_param));\r
             memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));\r
 \r
             if (g_os_param_reserved[0] == 1)\r
-                       {\r
-                               Log("break here for debug .....");\r
-                               goto End;\r
-                       }\r
+            {\r
+                Log("break here for debug .....");\r
+                goto End;\r
+            }\r
 \r
-                       // convert / to \\   \r
+            // convert / to \\   \r
             for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)\r
-                       {\r
+            {\r
                 if (g_os_param.vtoy_img_path[Pos] == '/')\r
-                               {\r
+                {\r
                     g_os_param.vtoy_img_path[Pos] = '\\';\r
-                               }\r
-                       }\r
+                }\r
+            }\r
 \r
-                       PeStart += sizeof(ventoy_os_param) + sizeof(ventoy_windows_data);\r
-                       sprintf_s(LunchFile, MAX_PATH, "ventoy\\%s", GetFileNameInPath(ExeFileName));\r
+            PeStart += sizeof(ventoy_os_param) + sizeof(ventoy_windows_data) + exlen;\r
+            sprintf_s(LunchFile, MAX_PATH, "ventoy\\%s", GetFileNameInPath(ExeFileName));\r
 \r
             MUTEX_LOCK(g_vtoyins_mutex);\r
             if (IsFileExist("%s", LunchFile))\r
@@ -1417,18 +2579,18 @@ int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
                 goto End;\r
             }\r
 \r
-                       SaveBuffer2File(LunchFile, Buffer + PeStart, FileSize - PeStart);\r
+            SaveBuffer2File(LunchFile, Buffer + PeStart, FileSize - PeStart);\r
             MUTEX_UNLOCK(g_vtoyins_mutex);\r
 \r
-                       break;\r
-               }\r
-       }\r
+            break;\r
+        }\r
+    }\r
 \r
-       if (PeStart >= FileSize)\r
-       {\r
-               Log("OS param not found");\r
-               goto End;\r
-       }\r
+    if (PeStart >= FileSize)\r
+    {\r
+        Log("OS param not found");\r
+        goto End;\r
+    }\r
 \r
     if (g_os_param_reserved[0] == 2)\r
     {\r
@@ -1441,106 +2603,29 @@ int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
 \r
 End:\r
 \r
-       if (Buffer)\r
-       {\r
-               free(Buffer);\r
-       }\r
-\r
-       return rc;\r
-}\r
-\r
-\r
-\r
-static int ventoy_append_process_id(const char *pidfile)\r
-{\r
-    DWORD PID = 0;\r
-    FILE *fp = NULL;\r
-\r
-    PID = GetCurrentProcessId();\r
-\r
-    fopen_s(&fp, pidfile, "a+");\r
-    if (!fp)\r
+    if (Buffer)\r
     {\r
-        return 1;\r
+        free(Buffer);\r
     }\r
 \r
-    fprintf_s(fp, "%u\n", PID);\r
-\r
-    fclose(fp);\r
-    return 0;\r
+    return rc;\r
 }\r
 \r
-static int ventoy_get_instance_id(const char *pidfile)\r
-{\r
-    int instance = 0;\r
-    FILE *fp = NULL;\r
-    char line[256];\r
-\r
-    fopen_s(&fp, pidfile, "r");\r
-    if (!fp)\r
-    {\r
-        return 1;\r
-    }\r
-\r
-    while (fgets(line, sizeof(line), fp))\r
-    {\r
-        instance++;\r
-    }\r
-\r
-    fclose(fp);\r
-    return instance + 1;\r
-}\r
 \r
-int main(int argc, char **argv)\r
+int real_main(int argc, char **argv)\r
 {\r
     int i = 0;\r
     int rc = 0;\r
-    int id = 0;\r
-    CHAR *Pos = NULL;\r
-    CHAR CurDir[MAX_PATH];\r
+    CHAR NewFile[MAX_PATH];\r
     CHAR LunchFile[MAX_PATH];\r
     CHAR CallParam[1024] = { 0 };\r
-    DWORD LockStatus = 0;\r
     STARTUPINFOA Si;\r
     PROCESS_INFORMATION Pi;\r
 \r
-    g_vtoylog_mutex = CreateMutexA(NULL, FALSE, "VTOYLOG_LOCK");\r
-    g_vtoyins_mutex = CreateMutexA(NULL, FALSE, "VTOYINS_LOCK");\r
-\r
-    MUTEX_LOCK(g_vtoyins_mutex);\r
-    if (IsFileExist(VTOY_PID_FILE))\r
-    {\r
-        id = ventoy_get_instance_id(VTOY_PID_FILE);\r
-    }\r
-    else\r
-    {\r
-        id = 1;\r
-    }\r
-    ventoy_append_process_id(VTOY_PID_FILE);\r
-    MUTEX_UNLOCK(g_vtoyins_mutex);\r
-\r
-    if (argv[0] && argv[0][0] && argv[0][1] == ':')\r
-    {\r
-        GetCurrentDirectoryA(sizeof(CurDir), CurDir);\r
-\r
-        strcpy_s(LunchFile, sizeof(LunchFile), argv[0]);\r
-        Pos = (char *)GetFileNameInPath(LunchFile);\r
-\r
-        strcat_s(CurDir, sizeof(CurDir), "\\");\r
-        strcat_s(CurDir, sizeof(CurDir), Pos);\r
-\r
-        if (_stricmp(argv[0], CurDir) != 0)\r
-        {\r
-            *Pos = 0;\r
-            SetCurrentDirectoryA(LunchFile);\r
-        }\r
-    }\r
-\r
-#ifdef VTOY_32\r
-    Log("######## VentoyJump 32bit [%d] ##########", id);\r
-#else\r
-    Log("######## VentoyJump 64bit [%d] ##########", id);\r
-#endif\r
+    Log("#### real_main #### argc = %d", argc);\r
+    Log("program full path: <%s>", g_prog_full_path);\r
+    Log("program dir: <%s>", g_prog_dir);\r
+    Log("program name: <%s>", g_prog_name);\r
 \r
     Log("argc = %d", argc);\r
     for (i = 0; i < argc; i++)\r
@@ -1553,51 +2638,29 @@ int main(int argc, char **argv)
         }\r
     }\r
 \r
-       if (Pos && *Pos == 0)\r
-       {\r
-               Log("Old current directory = <%s>", CurDir);\r
-               Log("New current directory = <%s>", LunchFile);\r
-       }\r
-       else\r
-       {\r
-               GetCurrentDirectoryA(sizeof(CurDir), CurDir);\r
-               Log("Current directory = <%s>", CurDir);\r
-       }\r
-\r
     GetStartupInfoA(&Si);\r
-\r
     memset(LunchFile, 0, sizeof(LunchFile));\r
 \r
-    if (strstr(argv[0], "vtoyjump.exe"))\r
-    {\r
-        rc = VentoyJumpWimboot(argc, argv, LunchFile);\r
-    }\r
-    else\r
-    {\r
-        rc = VentoyJump(argc, argv, LunchFile);\r
-    }\r
+    rc = VentoyJump(argc, argv, LunchFile);\r
 \r
-    Log("id=%d LunchFile=<%s> CallParam=<%s>", id, LunchFile, CallParam);\r
+    Log("LunchFile=<%s> CallParam=<%s>", LunchFile, CallParam);\r
 \r
-    if (id == 1 && _stricmp(argv[0], "PECMD.EXE") == 0 && _stricmp(LunchFile, "ventoy\\PECMD.EXE") == 0)\r
+    if (_stricmp(g_prog_name, "winpeshl.exe") != 0 && IsFileExist("ventoy\\%s", g_prog_name))\r
     {\r
-        MUTEX_LOCK(g_vtoyins_mutex);\r
-        id = ventoy_get_instance_id(VTOY_PID_FILE);\r
-        MUTEX_UNLOCK(g_vtoyins_mutex);\r
+        sprintf_s(NewFile, sizeof(NewFile), "%s\\VTOYJUMP.EXE", g_prog_dir);\r
+        MoveFileA(g_prog_full_path, NewFile);\r
+        Log("Move <%s> to <%s>", g_prog_full_path, NewFile);\r
 \r
-        Log("Current instance id is: %d", id);\r
+        sprintf_s(NewFile, sizeof(NewFile), "ventoy\\%s", g_prog_name);\r
+        CopyFileA(NewFile, g_prog_full_path, TRUE);\r
+        Log("Copy <%s> to <%s>", NewFile, g_prog_full_path);\r
 \r
-        if (id == 2)\r
-        {\r
-            MoveFileA("PECMD.EXE", "PECMD_BACK.EXE");\r
-            CopyFileA("ventoy\\PECMD.EXE", "PECMD.EXE", TRUE);            \r
-            sprintf_s(LunchFile, sizeof(LunchFile), "%s", "PECMD.EXE");\r
-            Log("Move original PECMD.EXE <%s>", LunchFile);\r
-        }\r
-        else\r
-        {\r
-            Log("%d instance started, don't move PECMD.EXE", id);\r
-        }\r
+        sprintf_s(LunchFile, sizeof(LunchFile), "%s", g_prog_full_path);\r
+        Log("Final lunchFile is <%s>", LunchFile);\r
+    }\r
+    else\r
+    {\r
+        Log("We don't need to recover original <%s>", g_prog_name);\r
     }\r
 \r
     if (g_os_param_reserved[0] == 3)\r
@@ -1616,19 +2679,24 @@ int main(int argc, char **argv)
             Log("Not setup.exe, hide windows.");\r
             Si.dwFlags |= STARTF_USESHOWWINDOW;\r
             Si.wShowWindow = SW_HIDE;\r
-        }        \r
+        }\r
 \r
         Log("Ventoy jump %s ...", rc == 0 ? "success" : "failed");\r
     }\r
-    \r
+\r
     Log("Now launch <%s> ...", LunchFile);\r
 \r
     if (g_os_param_reserved[0] == 4)\r
     {\r
         Log("Open cmd for debug ...");\r
+        Si.dwFlags |= STARTF_USESHOWWINDOW;\r
+        Si.wShowWindow = SW_NORMAL;\r
         sprintf_s(LunchFile, sizeof(LunchFile), "%s", "cmd.exe");\r
     }\r
 \r
+    Log("Backup log at this point");\r
+    CopyFileA(LOG_FILE, "X:\\Windows\\ventoy.backup", TRUE);\r
+\r
     CreateProcessA(NULL, LunchFile, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
 \r
     for (i = 0; rc && i < 1800; i++)\r
@@ -1642,5 +2710,133 @@ int main(int argc, char **argv)
     WaitForSingleObject(Pi.hProcess, INFINITE);\r
 \r
     Log("vtoyjump finished");\r
-       return 0;\r
+    return 0;\r
+}\r
+\r
+static void VentoyToUpper(CHAR *str)\r
+{\r
+    int i;\r
+    for (i = 0; str[i]; i++)\r
+    {\r
+        str[i] = (CHAR)toupper(str[i]);\r
+    }\r
+}\r
+\r
+static int vtoy_remove_duplicate_file(char *File)\r
+{\r
+    CHAR szCmd[MAX_PATH];\r
+    CHAR NewFile[MAX_PATH];\r
+    STARTUPINFOA Si;\r
+    PROCESS_INFORMATION Pi;\r
+\r
+    Log("<1> Copy New file", File);\r
+    sprintf_s(NewFile, sizeof(NewFile), "%s_NEW", File);\r
+    CopyFileA(File, NewFile, FALSE);\r
+\r
+    Log("<2> Remove file <%s>", File);\r
+    GetStartupInfoA(&Si);\r
+    Si.dwFlags |= STARTF_USESHOWWINDOW;\r
+    Si.wShowWindow = SW_HIDE;\r
+    sprintf_s(szCmd, sizeof(szCmd), "cmd.exe /c del /F /Q %s", File);\r
+    CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+    WaitForSingleObject(Pi.hProcess, INFINITE);\r
+\r
+    Log("<3> Copy back file <%s>", File);\r
+    MoveFileA(NewFile, File);\r
+\r
+    return 0;\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+    int i;\r
+    STARTUPINFOA Si;\r
+    PROCESS_INFORMATION Pi;\r
+    CHAR CurDir[MAX_PATH];\r
+    CHAR NewArgv0[MAX_PATH];\r
+    CHAR CallParam[1024] = { 0 };\r
+\r
+    g_vtoylog_mutex = CreateMutexA(NULL, FALSE, "VTOYLOG_LOCK");\r
+    g_vtoyins_mutex = CreateMutexA(NULL, FALSE, "VTOYINS_LOCK");\r
+\r
+    Log("######## VentoyJump %dbit ##########", g_system_bit);\r
+\r
+    GetCurrentDirectoryA(sizeof(CurDir), CurDir);\r
+    Log("Current directory is <%s>", CurDir);\r
+    \r
+    GetModuleFileNameA(NULL, g_prog_full_path, MAX_PATH);\r
+    split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);\r
+\r
+    Log("EXE path: <%s> dir:<%s> name:<%s>", g_prog_full_path, g_prog_dir, g_prog_name);\r
+\r
+    if (IsFileExist(WIMBOOT_FILE))\r
+    {\r
+        Log("This is wimboot mode ...");\r
+        g_wimboot_mode = TRUE;\r
+\r
+        if (!IsFileExist(WIMBOOT_DONE))\r
+        {\r
+            vtoy_remove_duplicate_file(g_prog_full_path);\r
+            SaveBuffer2File(WIMBOOT_DONE, g_prog_full_path, 1);\r
+        }\r
+    }\r
+    else\r
+    {\r
+        Log("This is normal mode ...");\r
+    }\r
+\r
+    if (_stricmp(g_prog_name, "WinLogon.exe") == 0)\r
+    {\r
+        Log("This time is rejump back ...");\r
+        \r
+        strcpy_s(g_prog_full_path, sizeof(g_prog_full_path), argv[1]);\r
+        split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);\r
+\r
+        return real_main(argc - 1, argv + 1);\r
+    }\r
+    else if (_stricmp(g_prog_name, "PECMD.exe") == 0)\r
+    {\r
+        strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_dir);\r
+        VentoyToUpper(NewArgv0);\r
+        \r
+        if (NULL == strstr(NewArgv0, "SYSTEM32") && IsFileExist(ORG_PECMD_BK_PATH))\r
+        {\r
+            Log("Just call original pecmd.exe");\r
+            strcpy_s(CallParam, sizeof(CallParam), ORG_PECMD_PATH);\r
+        }\r
+        else\r
+        {\r
+            Log("We need to rejump for pecmd ...");\r
+\r
+            ventoy_check_create_directory();\r
+            CopyFileA(g_prog_full_path, "ventoy\\WinLogon.exe", TRUE);\r
+\r
+            sprintf_s(CallParam, sizeof(CallParam), "ventoy\\WinLogon.exe %s", g_prog_full_path);\r
+        }\r
+        \r
+        for (i = 1; i < argc; i++)\r
+        {\r
+            strcat_s(CallParam, sizeof(CallParam), " ");\r
+            strcat_s(CallParam, sizeof(CallParam), argv[i]);\r
+        }\r
+\r
+        Log("Now rejump to <%s> ...", CallParam);\r
+        GetStartupInfoA(&Si);\r
+        CreateProcessA(NULL, CallParam, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);\r
+\r
+        Log("Wait rejump process...");\r
+        WaitForSingleObject(Pi.hProcess, INFINITE);\r
+        Log("rejump finished");\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        Log("We don't need to rejump ...");\r
+\r
+        ventoy_check_create_directory();\r
+        strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_full_path);\r
+        argv[0] = NewArgv0;\r
+\r
+        return real_main(argc, argv);\r
+    }\r
 }\r