forked from Mirrors/openclonk
Fix update procedure on Windows
by letting c4group wait for the Clonk process to terminate
parent
b471c22204
commit
f50972a9de
|
@ -42,8 +42,29 @@ bool C4Group_CopyEntry(C4Group *pFrom, C4Group *pTo, const char *strItemName)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool C4Group_ApplyUpdate(C4Group &hGroup)
|
||||
bool C4Group_ApplyUpdate(C4Group &hGroup, unsigned long ParentProcessID)
|
||||
{
|
||||
// Wait for parent process to terminate (so we can safely replace the executable)
|
||||
#ifdef _WIN32
|
||||
if(ParentProcessID)
|
||||
{
|
||||
HANDLE ParentProcess = OpenProcess(SYNCHRONIZE, FALSE, ParentProcessID);
|
||||
if(ParentProcess)
|
||||
{
|
||||
// If we couldn't find a handle then either
|
||||
// a) the process terminated already, which is great.
|
||||
// b) OpenProcess() failed, which is not so great. But let's still try to do
|
||||
// the update.
|
||||
printf("Waiting for parent process to terminate...");
|
||||
DWORD res = WaitForSingleObject(ParentProcess, 10000);
|
||||
if(res == WAIT_TIMEOUT)
|
||||
fprintf(stderr, "Parent process did not terminate after 10 seconds. Continuing...");
|
||||
}
|
||||
}
|
||||
#else
|
||||
// We could use waitpid on Unix, but we don't need that functionality there anyway...
|
||||
#endif
|
||||
|
||||
// Process object update group (GRPUP_Entries.txt found)
|
||||
C4UpdatePackage Upd;
|
||||
if (hGroup.FindEntry(C4CFN_UpdateEntries))
|
||||
|
@ -129,7 +150,7 @@ bool C4Group_ApplyUpdate(C4Group &hGroup)
|
|||
while (hGroup.FindNextEntry("*.c4u", strEntry))
|
||||
if (hChild.OpenAsChild(&hGroup, strEntry))
|
||||
{
|
||||
bool ok = C4Group_ApplyUpdate(hChild);
|
||||
bool ok = C4Group_ApplyUpdate(hChild, 0);
|
||||
hChild.Close();
|
||||
// Failure on child update
|
||||
if (!ok) return false;
|
||||
|
|
|
@ -72,6 +72,6 @@ protected:
|
|||
void WriteLog(const char *strMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
|
||||
};
|
||||
|
||||
bool C4Group_ApplyUpdate(C4Group &hGroup);
|
||||
bool C4Group_ApplyUpdate(C4Group &hGroup, unsigned long ParentProcessID);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -349,11 +349,29 @@ bool ProcessGroup(const char *FilenamePar)
|
|||
|
||||
// Apply an update
|
||||
case 'y':
|
||||
Log("Applying update...");
|
||||
if (C4Group_ApplyUpdate(hGroup))
|
||||
{ if (argv[iArg][2]=='d') fDeleteGroup = true; }
|
||||
else
|
||||
fprintf(stderr,"Update failed.\n");
|
||||
{
|
||||
Log("Applying update...");
|
||||
bool success = false;
|
||||
unsigned long pid = 0;
|
||||
bool have_pid = false;
|
||||
|
||||
if(iArg + 1 < argc)
|
||||
{
|
||||
errno = 0;
|
||||
pid = strtoul(argv[iArg+1], NULL, 10);
|
||||
if(errno == 0)
|
||||
have_pid = true;
|
||||
else
|
||||
pid = 0;
|
||||
}
|
||||
|
||||
if(C4Group_ApplyUpdate(hGroup, pid))
|
||||
{ if (argv[iArg][2]=='d') fDeleteGroup = true; }
|
||||
else
|
||||
fprintf(stderr,"Update failed.\n");
|
||||
|
||||
if(have_pid) ++iArg;
|
||||
}
|
||||
break;
|
||||
#ifdef _DEBUG
|
||||
case 'z':
|
||||
|
@ -578,7 +596,7 @@ int main(int argc, char *argv[])
|
|||
printf(" -p Pack -u Unpack -x Explode\n");
|
||||
printf(" -k Print maker\n");
|
||||
printf(" -g [source] [target] [title] Make update\n");
|
||||
printf(" -y Apply update\n");
|
||||
printf(" -y [ppid] Apply update (waiting for ppid to terminate first)\n");
|
||||
printf("\n");
|
||||
printf("Options: -v Verbose -r Recursive\n");
|
||||
printf(" -i Register shell -u Unregister shell\n");
|
||||
|
|
|
@ -189,7 +189,7 @@ bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4G
|
|||
strUpdateProg += ".exe";
|
||||
#endif
|
||||
// Determine name of local extract of update program
|
||||
StdStrBuf strUpdateProgEx; strUpdateProgEx.Copy(strUpdateProg);
|
||||
StdStrBuf strUpdateProgEx; strUpdateProgEx.Copy(Config.AtExePath(strUpdateProg.getData()));
|
||||
// Windows Vista/7: rename update program to setup.exe for UAC elevation and in temp path
|
||||
if (IsWindowsWithUAC()) strUpdateProgEx.Copy(Config.AtTempPath("setup.exe"));
|
||||
// Extract update program (the update should be applied using the new version)
|
||||
|
@ -198,6 +198,8 @@ bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4G
|
|||
if (!UpdateGroup.Open(strUpdateFile)) return false;
|
||||
// Look for update program at top level
|
||||
if (!UpdateGroup.ExtractEntry(strUpdateProg.getData(), strUpdateProgEx.getData()))
|
||||
return false;
|
||||
#if 0
|
||||
// ASK: What is this? Why should an update program not be found at the top
|
||||
// level? This seems obsolete. - Newton
|
||||
// Not found: look for an engine update pack one level down
|
||||
|
@ -208,15 +210,32 @@ bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4G
|
|||
SubGroup.ExtractEntry(strUpdateProg.getData(), strUpdateProgEx.getData());
|
||||
SubGroup.Close();
|
||||
}
|
||||
#endif
|
||||
UpdateGroup.Close();
|
||||
// Execute update program
|
||||
Log(LoadResStr("IDS_PRC_LAUNCHINGUPDATE"));
|
||||
succeeded = true;
|
||||
#ifdef _WIN32
|
||||
// Notice: even if the update program and update group are in the temp path, they must be executed in our working directory
|
||||
StdStrBuf strUpdateArgs; strUpdateArgs.Format("\"%s\" /p -w \"" C4ENGINECAPTION "\" -w \"" C4EDITORCAPTION "\" -w 2000 %s", strUpdateFile, fDeleteUpdate ? "-yd" : "-y");
|
||||
int iError = (intptr_t)ShellExecute(NULL, "open", strUpdateProgEx.getData(), strUpdateArgs.getData(), Config.General.ExePath, SW_SHOW);
|
||||
if (iError <= 32) return false;
|
||||
DWORD ProcessID = GetCurrentProcessId();
|
||||
StdStrBuf strUpdateArgs, strTitle;
|
||||
strUpdateArgs.Format("\"%s\" \"%s\" %s %lu", strUpdateProgEx.getData(), strUpdateFile, fDeleteUpdate ? "-yd" : "-y", (unsigned long)ProcessID);
|
||||
|
||||
STARTUPINFO startupInfo;
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
startupInfo.lpReserved = NULL;
|
||||
startupInfo.lpDesktop = NULL;
|
||||
startupInfo.lpTitle = "Updating OpenClonk...";
|
||||
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startupInfo.wShowWindow = SW_SHOW;
|
||||
startupInfo.cbReserved2 = 0;
|
||||
startupInfo.lpReserved2 = NULL;
|
||||
PROCESS_INFORMATION procInfo;
|
||||
BOOL success = CreateProcess(strUpdateProgEx.getData(), strUpdateArgs.getMData(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, Config.General.ExePath, &startupInfo, &procInfo);
|
||||
if(!success) return false;
|
||||
|
||||
//int iError = (intptr_t)ShellExecute(NULL, "open", strUpdateProgEx.getData(), strUpdateArgs.getData(), Config.General.ExePath, SW_SHOW);
|
||||
//if (iError <= 32) return false;
|
||||
// must quit ourselves for update program to work
|
||||
if (succeeded) Application.Quit();
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue