FAQ:WinAPI VCPP:самообновление запущенной программы

Материал из Весельчак У
Перейти к: навигация, поиск

Каким способом exe файл может заменить самого себя?

К примеру, программа должна обновляется через Internet и хочет обновить свой exe-файл. Но так как он в данный момент запущен, это будет, естественно, невозможно сделать напрямую. Один из способов - сделать копию экзешника и из него обновиться

// путь к старому файлу
#define def_exeNAMEup	"c:\\myprog_toupdate.exe"
 
// путь к новому файлу (уже "скачали":) )
#define def_exeNAMEdnld	"c:\\myprog_downloaded.exe"
 
#define def_keyUdate	"/update"
 
void CTESTFAQApp::UpdateItself()
{
	// добыча полного имени экзешника
	CString csFullExeName;
	{
		CString csAppName = GetCommandLine();
		csAppName.Delete(0,1);
		csAppName.Replace('\"', '\0');
		csFullExeName = (const char*)csAppName;
	}
	// теперь csFullExeName - содержит искомый путь
 
	// делаем копию экзешника с другим именем
	CopyFile(csFullExeName, def_exeNAMEup, 0);
 
	// передаём в параметры нового процесса ключ и путь к текущему файлу
	CString csParams = def_keyUdate;
 
	csParams += " ";
	csParams += csFullExeName;
 
	// запускаем копию
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
 
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));
 
	if (CreateProcess(def_exeNAMEup, def_keyUdate, 0, 0, 0, 0, 0, 0, &si, &pi))
	{
		// завершаем текущий процесс
		ExitFromMyApp();
	}
}
 
void CTESTFAQApp::ExitFromMyApp()
{
	exit(0);
}
 
BOOL CTESTFAQApp::InitInstance()
{
	// смотрим, не запущено ли для апдейта?
	CString txt;
 
	txt = m_lpCmdLine;
 
	if (txt.Find(def_keyUdate) == 0)
	{
		// делаем айдейт
		txt.Replace(def_keyUdate, "");
		txt.TrimLeft();
 
		CString csFullExeName = txt;
 
		// берём откуда то уже скачанный файл обновления
		// ...
		CString csFull_Downloaded_ExeName = def_exeNAMEdnld;
 
		// копируем файл (обновляем старый то есть)
		CopyFile(csFull_Downloaded_ExeName, csFullExeName, 0);
 
		// запускаем обновлённого мученника
		STARTUPINFO si;
		PROCESS_INFORMATION pi;
 
		ZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);
		ZeroMemory(&pi, sizeof(pi));
 
		if (CreateProcess(csFullExeName, 0, 0, 0, 0, 0, 0, 0, &si, &pi))
			ExitFromMyApp();
	}
 
	// ...
	// ...
}