void PlayerSlots::Unpatch() { L4D_DEBUG_LOG("PlayersSlots - Unpatching ..."); //jl around the string "Human player limit reached (%d/%d)" // Windows only #if defined PLATFORM_WINDOWS if(humanLimitSig) { ApplyPatch(humanLimitSig, /*offset*/0, &humanLimitRestore, /*restore*/NULL); L4D_DEBUG_LOG("PlayerSlots -- 'HumanPlayerLimitReached' jl(e) restored"); } #endif //jz around the string "#Valve_Reject_Server_Full" if(lobbyConnectSig) { ApplyPatch(lobbyConnectSig, /*offset*/0, &lobbyConnectRestore, /*restore*/NULL); L4D_DEBUG_LOG("PlayerSlots -- 'ConnectClientLobbyCheck' restored"); } PlayerSlots::UnpatchSlotCheckOnly(); PlayerSlots::UnpatchGetMaxHumanPlayers(); //PlayerSlots::UnpatchGetTotalNumPlayersSupported(); }
void CommandTable::Init(void) { // read in the console commands g_consoleCommands.SetBaseID(0x0100); g_consoleCommands.Read((CommandInfo *)g_offsetConsoleCommandsStart, (CommandInfo *)g_offsetConsoleCommandsLast); // read in the script commands g_scriptCommands.SetBaseID(0x1000); g_scriptCommands.Read((CommandInfo *)g_offsetScriptCommandsStart, (CommandInfo *)g_offsetScriptCommandsLast); // pad to opcode 0x1400 to give Bethesda lots of room g_scriptCommands.PadTo(kNVSEOpcodeStart); // Add NVSE Commands g_scriptCommands.AddCommandsV1(); #if _DEBUG g_scriptCommands.AddDebugCommands(); #endif // register plugins g_pluginManager.Init(); ApplyPatch(kPatch_ScriptCommands_Start, (UInt32)g_scriptCommands.GetStart()); ApplyPatch(kPatch_ScriptCommands_End, (UInt32)g_scriptCommands.GetEnd()); ApplyPatch(kPatch_ScriptCommands_MaxIdx, g_scriptCommands.GetMaxID()); _MESSAGE("max id = %08X", g_scriptCommands.GetMaxID()); g_scriptCommands.Dump(); _MESSAGE("patched"); }
void CommandTable::Init(void) { static CommandInfo* kCmdInfo_Unused_1; #if RUNTIME #if RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525 kCmdInfo_Unused_1 = (CommandInfo*)0x0118E4F8; #elif RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525ng kCmdInfo_Unused_1 = (CommandInfo*)0x0118E4F8; #else #error #endif #else kCmdInfo_Unused_1 = (CommandInfo*)0x00E9D7A0; #endif // read in the console commands g_consoleCommands.SetBaseID(0x0100); g_consoleCommands.Read((CommandInfo *)g_offsetConsoleCommandsStart, (CommandInfo *)g_offsetConsoleCommandsLast); // read in the script commands g_scriptCommands.SetBaseID(0x1000); g_scriptCommands.Read((CommandInfo *)g_offsetScriptCommandsStart, (CommandInfo *)g_offsetScriptCommandsLast); // blocktype "Unused_1" becomes "Function" UInt16 onUnused_1Opcode = kCmdInfo_Unused_1->opcode; *kCmdInfo_Unused_1 = kCommandInfo_Function; kCmdInfo_Unused_1->opcode = onUnused_1Opcode; // pad to opcode 0x1400 to give Bethesda lots of room g_scriptCommands.PadTo(kNVSEOpcodeStart); // Add NVSE Commands g_scriptCommands.AddCommandsV1(); g_scriptCommands.AddCommandsV3s(); g_scriptCommands.AddCommandsV4(); #if _DEBUG g_scriptCommands.AddDebugCommands(); #endif // register plugins g_pluginManager.Init(); // patch the code ApplyPatch(kPatch_ScriptCommands_Start, (UInt32)g_scriptCommands.GetStart()); ApplyPatch(kPatch_ScriptCommands_End, (UInt32)g_scriptCommands.GetEnd()); ApplyPatch(kPatch_ScriptCommands_MaxIdx, g_scriptCommands.GetMaxID()); ApplyPatchEditorOpCodeDataList(); _MESSAGE("max id = %08X", g_scriptCommands.GetMaxID()); _MESSAGE("console commands"); g_consoleCommands.Dump(); _MESSAGE("script commands"); g_scriptCommands.Dump(); _MESSAGE("patched"); }
/* Patch CTerrorGameRules::GetMaxHumanPlayers(void) to always return our own value This will cause server browsers to display our own 'max players' value (Linux only) On Windows overriding it does nothing at first.. but actually it breaks scavenge mode which is stuck in a 'scavenge versus' type mode so it should NEVER BE PATCHED FOR WINDOWS EVER On Linux just overriding ServerPlayerCounts isn't enough (it only fixes 'status' command) but overwriting GetMaxHumanPlayers works great */ void PlayerSlots::PatchGetMaxHumanPlayers() { #if !defined PLATFORM_WINDOWS bool firstTime = (getMaxHumanPlayersSig == NULL); if(firstTime) { if (!g_pGameConf->GetMemSig("GetMaxHumanPlayers", &getMaxHumanPlayersSig) || !getMaxHumanPlayersSig) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'GetMaxHumanPlayers' signature"); return; } } /* Normally CTerrorGameRules::GetMaxHumanRules(void) returns CTerrorGameRules::IsVersusMode() ? 8 : 4 we just want it to return our own PLAYER_SLOTS_MAX always though */ /* The trick here is just to patch the function to: mov eax, PLAYER_SLOTS_MAX retn Now it will always return our value instead of 4 or 8 */ patch_t getMaxHumanPlayersPatch; getMaxHumanPlayersPatch.bytes = OP_MOV_EAX_IMM32_SIZE + OP_RETN_SIZE; // mov eax, PLAYER_SLOTS_MAX getMaxHumanPlayersPatch.patch[0] = OP_MOV_EAX_IMM32; *(uint32_t*)(getMaxHumanPlayersPatch.patch+sizeof(uint8_t)) = (uint32_t)PLAYER_SLOTS_MAX; // retn getMaxHumanPlayersPatch.patch[OP_MOV_EAX_IMM32_SIZE] = OP_RETN; if(firstTime) { ApplyPatch(getMaxHumanPlayersSig, /*offset*/0, &getMaxHumanPlayersPatch, &getMaxHumanPlayersRestore); } else { ApplyPatch(getMaxHumanPlayersSig, /*offset*/0, &getMaxHumanPlayersPatch, /*restore*/NULL); } L4D_DEBUG_LOG("PlayerSlots -- 'GetMaxHumanPlayers' patched to MOV eax, %d; retn", PLAYER_SLOTS_MAX); #endif }
//=--------------------------------------------------------------------------= // CPatchDialog::PatchUpdateThreadProc //=--------------------------------------------------------------------------= // Thread procedure for applying the patch // // Parameters: // lpParameter Thread parameter // // Output: // DWORD // // Notes: // DWORD WINAPI CPatchDialog::PatchUpdateThreadProc(LPVOID lpParameter) { CPatchDialog* pDlg = (CPatchDialog *) lpParameter; g_pDlg = pDlg; BOOL bSuccess = FALSE; do { // Check if download has been cancelled if (WAIT_OBJECT_0 == WaitForSingleObject(pDlg->m_hCancelEvent, 0)) break; bSuccess = ApplyPatch(m_szDirectory, m_szOptions, PatchUpdateCallBack); } while (0); // Post message to main thread to dis-miss dialog if users haven't hit cancel // if (WAIT_OBJECT_0 != WaitForSingleObject(pDlg->m_hCancelEvent, 0)) { if (bSuccess) ::PostMessage(pDlg->m_hWnd, WM_COMMAND, IDOK, NULL); else ::PostMessage(pDlg->m_hWnd, WM_COMMAND, IDCANCEL, NULL); } // Signal main thread ::SetEvent(pDlg->m_hPatchUpdateThreadExitEvent); return 0; }
void SysCoreThread::GameStartingInThread() { GetMTGS().SendGameCRC(ElfCRC); if (EmuConfig.EnablePatches) ApplyPatch(0); if (EmuConfig.EnableCheats) ApplyCheat(0); }
bool ApplyPatch(PatchTree *child, bool success, Sequence *branchTree, DWORD dwVersionLS, bool isMorrowind, int hInstanceOffset) { PatchTree *patch = child; if(!patch) return success; do { if( !( (patch->FileVersion?(*patch->FileVersion)!=dwVersionLS:DEFAULTFILEVER!=dwVersionLS) || (patch->Removed?(*patch->Removed):false) || (patch->Checked?!(*patch->Checked):false) ) ) { char *message = NULL; Sequence **branch = NULL; if(patch->Original ? !MachineCode::CompareOriginal(patch->Original, hInstanceOffset) : false) { message = strcat(strcat(strcpy(new char[MAX_PATH], "Patch: Original code is different for section \""), patch->Section), "\""); }else if(patch->Attach ? !(branch = MachineCode::SetAttach(patch->Attach, &branchTree, hInstanceOffset)) : false) { message = strcat(strcat(strcpy(new char[MAX_PATH], "Patch: Problems in section \""), patch->Attach->String), "\""); }else if(patch->Patch ? !MachineCode::SetPatch(patch->Patch, branchTree, hInstanceOffset) : false) { message = strcat(strcat(strcpy(new char[MAX_PATH], "Patch: Problems with patch applying in section \""), patch->Section), "\""); }else success = ApplyPatch(patch->Child, success, branchTree, dwVersionLS, isMorrowind, hInstanceOffset) ? success : false; if(message) { if(success && !isMorrowind) Logger::CreateLogFile(PATCH_LOG_NAME); _LogLine(message); success = false; delete[] message; } if(branch) { delete (*branch); (*branch) = NULL; } } }while(patch = patch->Next); return success; }
int TestPatchInMemory(int argc,char *argv[]) { FILE *patchFile, *newFile, *oldFile; char *patch,*_new,*old; unsigned patchSize, oldSize; unsigned int newSize; int res; if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); patchFile=fopen(argv[3], "rb"); newFile=fopen(argv[2], "wb"); oldFile=fopen(argv[1], "rb"); fseeko(patchFile, 0, SEEK_END); fseeko(oldFile, 0, SEEK_END); patchSize=ftell(patchFile); oldSize=ftell(oldFile); fseeko(patchFile, 0, SEEK_SET); fseeko(oldFile, 0, SEEK_SET); patch = new char [patchSize]; old = new char [oldSize]; fread(patch, patchSize, 1, patchFile); fread(old, oldSize, 1, oldFile); res = ApplyPatch( old, oldSize, &_new, &newSize,patch, patchSize); fwrite(_new, newSize, 1, newFile); fclose(patchFile); fclose(newFile); fclose(oldFile); return res; }
void PlayerSlots::UnpatchGetMaxHumanPlayers() { if(getMaxHumanPlayersSig) { ApplyPatch(getMaxHumanPlayersSig, /*offset*/0, &getMaxHumanPlayersRestore, /*restore*/NULL); L4D_DEBUG_LOG("PlayerSlots -- 'GetMaxHumanPlayers' restored"); } }
void CDetour::DisableDetour() { if (detoured) { /* Remove the patch */ ApplyPatch(detour_address, 0, &detour_restore, NULL); detoured = false; } }
void AddonsDisabler::Unpatch() { L4D_DEBUG_LOG("AddonsDisabler - Unpatching ..."); if (vanillaModeSig) { ApplyPatch(vanillaModeSig, /*offset*/4, &vanillaModeSigRestore, /*restore*/NULL); L4D_DEBUG_LOG("AddonsDisabler -- 'VanillaModeOffset' restored"); } }
void PlayerSlots::UnpatchSlotCheckOnly() { //cmp around the string "#Valve_Reject_Server_Full" if(lobbyConnectSig && serverFullOffset != -1) { ApplyPatch(lobbyConnectSig, serverFullOffset, &serverFullRestore, /*restore*/NULL); L4D_DEBUG_LOG("PlayerSlots -- 'ValveRejectServerFullFirst' restored"); } }
void GameplayPatches(void) { // originally supposed to be 100 /decimal/ but oops UInt8 kPickpocketChance[] = { 0xB8, 0x00, 0x01, 0x00, 0x00, // mov eax, 0x0100 0xC3 // retn }; ApplyPatch(0x00598DB0, kPickpocketChance, sizeof(kPickpocketChance)); SafeWrite8(0x008F0850, 0xC3); // disable achievements }
void PatchModuleMemory(HINSTANCE hModule, LPSTR lpFilename, bool isMorrowind) { if(!lpPatchTree || !hModule || !lpFilename) return; PatchTree *file = lpPatchTree; do { if((_stricmp(lpFilename, file->Section)==0)&&(file->Removed?!(*file->Removed):true)&&(file->Checked?(*file->Checked):true)&&file->Child) { if(ApplyPatch(file->Child, true, NULL, GetModuleNameAndVersion(hModule,NULL,NULL), isMorrowind, DWORD(hModule)-DEFAULT_INSTANCE_DLL)) { if(isMorrowind) _LogLine("Patch has been applied to %s successfully", file->Section); } break; } }while(file = file->Next); return; }
void CriticalHitManager::DisableCriticalDetour() { if (critical_callback) { /* Remove the patch */ ApplyPatch(critical_address, 0, &critical_restore, NULL); detoured = false; } if (melee_callback) { /* Remove the patch */ ApplyPatch(melee_address, 0, &melee_restore, NULL); detoured = false; } if (knife_callback) { /* Remove the patch */ ApplyPatch(knife_address, 0, &knife_restore, NULL); detoured = false; } }
void PatchProcessMemory(HINSTANCE hModule, LPSTR origFilename, DWORD dwVersionLS, bool isMorrowind) { HINSTANCE hInstance = hModule;//GetModuleHandleA(NULL); if(lpPatchTree && hInstance && hModule && origFilename) {} else return; PatchTree *file = lpPatchTree; do { HINSTANCE hModuleInstance = _stricmp(origFilename, file->Section)==0 ? hModule : GetModuleHandleA(file->Section); if(hModule == hInstance && (_stricmp(TEXT_DLL_NAME, file->Section)==0 || _stricmp(MWE_DLL_NAME, file->Section)==0)) continue; if(hModuleInstance && (file->Removed?!(*file->Removed):true) && (file->Checked?(*file->Checked):true) && file->Child) { if(ApplyPatch(file->Child, true, NULL, hModuleInstance == hInstance ? dwVersionLS : GetModuleNameAndVersion(hModuleInstance, NULL, NULL), isMorrowind, DWORD(hModuleInstance) - (hModuleInstance == hInstance ? DEFAULT_INSTANCE_EXE : DEFAULT_INSTANCE_DLL ))) { if(isMorrowind) _LogLine("Patch has been applied to %s successfully", file->Section); } } }while(file = file->Next); return; }
int __cdecl EnableucrtFreadWorkaround() { // This patches ucrtbase such that fseek will always // synchronize the file object's internal buffer. bool applied_at_least_one = false; for (const auto &patch : s_patches) { if (ApplyPatch(patch)) { applied_at_least_one = true; } } /* For forward compat, do not fail if patches don't apply (e.g. version mismatch) if (!applied_at_least_one) { std::abort(); } //*/ return 0; }
void AddonsDisabler::Patch() { L4D_DEBUG_LOG("AddonsDisabler - Patching ..."); bool firstTime = (vanillaModeSig == NULL); if (firstTime) { if (!g_pGameConf->GetMemSig("VanillaModeOffset", &vanillaModeSig) || !vanillaModeSig) { g_pSM->LogError(myself, "AddonsDisabler -- Could not find 'VanillaModeOffset' signature"); return; } } patch_t vanillaModePatch; vanillaModePatch.bytes = 3; // mov esi+19h -> NOP vanillaModePatch.patch[0] = 0x0f; vanillaModePatch.patch[1] = 0x1f; vanillaModePatch.patch[2] = 0x00; ApplyPatch(vanillaModeSig, /*offset*/4, &vanillaModePatch, /*restore*/firstTime ? &vanillaModeSigRestore : NULL); L4D_DEBUG_LOG("AddonsDisabler -- 'VanillaModeOffset' patched to NOP"); }
void PlayerSlots::Patch() { #if defined PLATFORM_WINDOWS bool firstTime = !(humanLimitSig && lobbyConnectSig); #else bool firstTime = !(lobbyConnectSig); #endif L4D_DEBUG_LOG("PlayerSlots - Patching ..."); /* Server patch ** Needed on windows only. On Linux, this called GetMaxHumanPlayers L4DToolZ doesn't patch this anymore? */ #if defined PLATFORM_WINDOWS if(firstTime) { if (!g_pGameConf->GetMemSig("HumanPlayerLimitReached", &humanLimitSig) || !humanLimitSig) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'HumanPlayerLimitReached' signature"); return; } } //code pages can't be written to by default, so ApplyPatch changes that ;) /* jl around the string "Human player limit reached (%d/%d)" jl -> jmp (Windows) jle -> nop (Linux) we never check if the human player limit has been reached */ patch_t humanLimitPatch; //#if defined PLATFORM_WINDOWS humanLimitPatch.bytes = 1; humanLimitPatch.patch[0] = OP_JMP_REL8; //#else //PLATFORM_LINUX // humanLimitPatch.bytes = OP_JLE_REL8_SIZE; // fill_nop(humanLimitPatch.patch, humanLimitPatch.bytes); //#endif ApplyPatch(humanLimitSig, /*offset*/0, &humanLimitPatch, firstTime ? &humanLimitRestore : NULL); L4D_DEBUG_LOG("PlayerSlots -- 'HumanPlayerLimitReached' jl(e) patched to jmp"); #endif /* Engine patch */ if (!g_pGameConf->GetMemSig("ConnectClientLobbyCheck", &lobbyConnectSig) || !lobbyConnectSig) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'ConnectClientLobbyCheck' signature"); return; } #if defined PLATFORM_WINDOWS /* jz around the string "#Valve_Reject_Server_Full" jz -> nop (linux or windows) do not skip to the server is full code when sv_allow_lobby_connect is 0 */ patch_t lobbyConnectPatch; lobbyConnectPatch.bytes = OP_JZ_REL8_SIZE; fill_nop(lobbyConnectPatch.patch, OP_JZ_REL8_SIZE); ApplyPatch(lobbyConnectSig, /*offset*/0, &lobbyConnectPatch, firstTime ? &lobbyConnectRestore : NULL); unsigned char oldValue2 = lobbyConnectRestore.patch[0]; L4D_DEBUG_LOG("PlayerSlots -- 'ConnectClientLobbyCheck' jz(%x) patched to 2 nops", oldValue2); #endif }
// This is called from the PS2 VM at the start of every vsync (either 59.94 or 50 hz by PS2 // clock scale, which does not correlate to the actual host machine vsync). // // Default tasks: Updates PADs and applies vsync patches. Derived classes can override this // to change either PAD and/or Patching behaviors. // // [TODO]: Should probably also handle profiling and debugging updates, once those are // re-implemented. // void SysCoreThread::VsyncInThread() { if (EmuConfig.EnablePatches) ApplyPatch(); if (EmuConfig.EnableCheats) ApplyCheat(); }
void PlayerSlots::PatchSlotCheckOnly() { if(!lobbyConnectSig) return; //avoid a null dereference if we failed to lookup the sig bool firstTime = (serverFullOffset == -1); if(firstTime) { ////////////////////////// //valve reject server full if (!g_pGameConf->GetOffset("ValveRejectServerFullFirst", &serverFullOffset)) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'ValveRejectServerFullFirst' offset"); return; } //the offset should point to the cmp eax, [esi+180h]... first byte incorrect => wrong offset if(*((uint8_t*)lobbyConnectSig + serverFullOffset) != OP_CMP_R32_RM32) { g_pSM->LogError(myself, "PlayerSlots -- Offset for 'ValveRejectServerFullFirst' is incorrect"); return; } } /* cmp around the string "#Valve_Reject_Server_Full" cmp eax, [esi+180h] -> cmp eax, IMM32(PLAYER_SLOTS_MAX) (Windows) cmp esi, [ebx+17Ch] -> cmp esi, IMM32(PLAYER_SLOTS_MAX) (Linux) we effectively change how many max players we allow */ patch_t serverFullPatch; #if defined PLATFORM_LINUX serverFullPatch.bytes = OP_CMP_RM32_IMM32_SIZE; serverFullPatch.patch[0] = OP_CMP_RM32_IMM32; serverFullPatch.patch[MODRM_BYTE] = MODRM_MOD_DIRECT | OP_CMP_RM32_IMM32_MODRM_DIGIT | MODRM_RM_ESI; //0xFF *(uint32_t*)(serverFullPatch.patch+MODRM_BYTE+sizeof(uint8_t)) = (uint32_t)PLAYER_SLOTS_MAX; #else //PLATFORM_WINDOWS serverFullPatch.bytes = OP_CMP_R32_RM32_SIZE; //replace the first part of cmp eax, [esi+180h] with cmp eax, IMM32(player_slots_max) serverFullPatch.patch[0] = OP_CMP_EAX_IMM32; *(uint32_t*)(serverFullPatch.patch+sizeof(uint8_t)) = (uint32_t)PLAYER_SLOTS_MAX; //fill in the rest of the patch size with nops fill_nop(serverFullPatch.patch + OP_CMP_EAX_IMM32_SIZE, OP_CMP_R32_RM32_SIZE - OP_CMP_EAX_IMM32_SIZE); #endif if(firstTime) { ApplyPatch(lobbyConnectSig, serverFullOffset, &serverFullPatch, &serverFullRestore); } else { ApplyPatch(lobbyConnectSig, serverFullOffset, &serverFullPatch, /*restore*/NULL); } L4D_DEBUG_LOG("PlayerSlots -- 'ValveRejectServerFullFirst' patched to CMP eax, %d", PLAYER_SLOTS_MAX); // L4D_DEBUG_LOG("PlayerSlots -- CBaseServer player limit: %d", *(unsigned int *)((int)g_pServer+ 0x17C)); }
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/) { #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); #else HRESULT hRes = CoInitialize(NULL); #endif _ASSERTE(SUCCEEDED(hRes)); _Module.Init(ObjectMap, hInstance, NULL); int nRet = 0; // Various mode of operation BOOL bSilentMode = FALSE; TCHAR szTargetBaseVersionInfo[256]; TCHAR szTargetNewVersionInfo[256]; // Open patch trace file OPEN_PATCH_TRACEFILE(); do { TCHAR szDirectory[BUFFER_SIZE]; szDirectory[0] = NULL; //--------------------------------------------------- // Parse parameters from command line // if ((__argc == 2) || (__argc == 3 && lstrcmpi(__argv[1], TEXT("-s")) == 0)) { // jupdate [-s] dir (Apply patch) // wsprintf(szDirectory, "%s", __argv[__argc - 1]); //--------------------------------------------------- // Remove trailing '\' in path (#4689837) // int iPathLen = lstrlen(szDirectory); if (szDirectory[iPathLen - 1] == '\\' || szDirectory[iPathLen - 1] == '\"') szDirectory[iPathLen - 1] = NULL; if (__argc == 3) bSilentMode = TRUE; } else { // Invalid options nRet = UPDATE_ERROR_OPTIONS; break; } //--------------------------------------------------- // Check if VM is running // UINT uRet = IDRETRY; while (IsVMRunning(szDirectory) && uRet == IDRETRY) { /* // Should not ask user if we are in silent mode if (bSilentMode) { nRet = UPDATE_ERROR_VM_RUNNING; break; } else */ { TCHAR szBuffer[BUFFER_SIZE], szMessage[BUFFER_SIZE], szCaption[BUFFER_SIZE]; ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_VM_RUNNING, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_WARNING, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION); uRet = MessageBox(NULL, szMessage, szCaption, MB_RETRYCANCEL | MB_ICONWARNING); } } // Make sure we break out of the loop if (nRet == UPDATE_ERROR_VM_RUNNING) break; if (uRet == IDCANCEL) { nRet = UPDATE_ERROR_VM_RUNNING; break; } //--------------------------------------------------- // Retrieve version info of patched image and base image // // Retrieve version info of base image if (RetrievePatchInfo(szDirectory, szTargetBaseVersionInfo) == FALSE) { // Cannot locate version.dat nRet = UPDATE_ERROR_VERSIONINFO; break; } wsprintf(szTargetNewVersionInfo, "%s", szTargetBaseVersionInfo); // Check if directory has been patched // /* if (stricmp(szTargetNewVersionInfo, NEW_IMAGE_FULLVERSION) == 0) { nRet = UPDATE_ERROR_SAME_VERSION_INSTALLED; break; // Check if a newer patch has been installed else if (stricmp(szTargetNewBuildNumber, NEW_IMAGE_BUILD_NUMBER) > 0) { nRet = UPDATE_ERROR_NEWER_VERSION_INSTALLED; break; } } */ //----------------------------------------- // Perform actual patching // // If we can't found the base image, see if the targeted directory // can be used as the base image if (stricmp(szTargetBaseVersionInfo, BASE_IMAGE_FULLVERSION) != 0 && stricmp(szTargetBaseVersionInfo, NEW_IMAGE_FULLVERSION) != 0) { // Cannot locate any valid base image nRet = UPDATE_ERROR_INVALID_BASE_IMAGE; break; } if (bSilentMode) { // Patch silently if (ApplyPatch(szDirectory, "", SilentUpdateCallBack) == FALSE) { nRet = UPDATE_ERROR_PATCH; break; } } else { // Patch installer dialog CPatchDialog dlg; // Set directory to apply the patch dlg.setCommandLine(szDirectory, NULL); // Execute Installation ... if (dlg.DoModal() != IDOK) { nRet = UPDATE_ERROR_PATCH; break; } } } while (0); // Show dialogs for success/failure // TCHAR szBuffer[BUFFER_SIZE], szMessage[BUFFER_SIZE], szCaption[BUFFER_SIZE]; switch (nRet) { case 0: { ::LoadString(_Module.GetResourceInstance(), IDS_INSTALL_SUCCESS, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_SUCCEEDED, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION); DisplayInfo(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_OPTIONS: { ::LoadString(_Module.GetResourceInstance(), IDS_OPTIONS, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); char* lpszPath = strrchr(__argv[0], '\\'); if (lpszPath != NULL) wsprintf(szMessage, szBuffer, lpszPath + 1); else wsprintf(szMessage, szBuffer, __argv[0]); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_PATCH: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_UPDATE, szMessage, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_VERSIONINFO: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_VERSIONINFO, szMessage, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_INVALID_BASE_IMAGE: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_BASE_IMAGE_NOT_FOUND, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, BASE_IMAGE_FULLVERSION); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_SAME_VERSION_INSTALLED: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_INSTALLED_SAME_VERSION, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_SUCCEEDED, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION); DisplayInfo(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_NEWER_VERSION_INSTALLED: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_INSTALLED_NEWER_VERSION, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, szTargetNewVersionInfo); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_WRONG_VERSION_UNINSTALLED: { ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_UNINSTALL_WRONG_VERSION, szBuffer, BUFFER_SIZE); ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE); wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, szTargetNewVersionInfo); DisplayError(bSilentMode, szMessage, szCaption); break; } case UPDATE_ERROR_VM_RUNNING: { PATCH_TRACE("FAIL: VM is currently running.\n"); break; } }; // Close patch trace file CLOSE_PATCH_TRACEFILE(); _Module.Term(); CoUninitialize(); if (nRet == 0) return 0; else return ERROR_INSTALL_FAILURE; }