背景:
在游戏程序的开发中,经常会碰到这样的情况,运行游戏更新程序后需要重新启动更新程序,在游戏内修改视频等相关设置后需要重新启动游戏程序,这样的操作该如何实现呢?
解决方案:
一种解决方案是通过等待来启动新的程序,但是这样的实现方式在极端情况下会出现问题,假设某游戏程序每次在一个物理机上只允许启动一个进程,如果关闭旧的进程因为一些原因而造成延迟,那么启动新的进程时会失败,试想游戏更新程序结束后,提示玩家游戏将重启,而游戏并没有重启,这种体验是相当糟糕的。
另一种解决方案,为了保证程序A关闭后与程序B再打开,在windows环境下有一种很常用的方法——批处理,由于批处理中的方法都是顺序执行的,关闭程序A打开程序B的操作可以保证同步执行,将杀死进程与启动进程的功能写入批处理,在需要重启的地方,调用API执行该批处理即可。
- /*
- author: coffeecat
- brief : All the code below has been tested.
- date : 2014/10/21
- */
- #include "stdafx.h"
- #include <iostream>
- using namespace std;
- void Restart()
- {
- FILE* pf;
- ::DeleteFile(L"restart.cmd"); //确保删除上次遗留下的批处理文件
- errno_t err = ::_wfopen_s(&pf, L"restart.cmd", L"w"); //“w”表示打开一个空文件以进行写入。如果该文件存在,其内容将被销毁。
- if( err == 0 ) //restart.cmd不存在时,err == 0
- {
- char szExeName[1024];
- GetModuleFileNameA( NULL, szExeName, 1024); //获取进程的名称
- fprintf( pf, "@echo off\n:a\n taskkill /f /im restart.exe \n start \"\" \"%s\" \ndel %%0", szExeName);
- //restart.exe为需要重启的进程名称
- //taskkill /f(指定要强行终止的进程) /im( image name 可以理解为指定要终止的进程名名称)
- //%%0在批处理中表示%0,del %%0(删除批处理自身)
- fclose( pf );
- }
- else
- {
- cout << "can not open restart.cmd" << endl;
- }
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- ZeroMemory( &si, sizeof si );
- ZeroMemory( &pi, sizeof pi );
- si.cb = sizeof si;
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE;
- TCHAR winSysDir[1024];
- ZeroMemory( winSysDir, sizeof winSysDir );
- ::GetSystemDirectory( winSysDir, 1024 );
- std::wstring appName = winSysDir;
- appName += L"\\cmd.exe";
- BOOL bRet = CreateProcess(
- appName.c_str(),
- L"/c restart.cmd", //执行字符串指定的命令然后终断
- NULL,
- NULL,
- FALSE,
- 0,
- NULL,
- NULL,
- &si,
- &pi);
- if ( bRet == FALSE )
- {
- int err = GetLastError();
- cout << "can not restart test, error code:" << err << endl;
- }
- }
- int main()
- {
- int input, curPid;
- curPid = GetCurrentProcessId();
- cout << "Current process Id:" << curPid << endl;
- cout << "Do you need to restart the program ? (input 1 for restart, else do not restart)" << endl;
- cin >> input;
- if (input == 1)
- {
- Restart();
- }
- system("pause");
- return 0;
- }
执行上述代码,输入1会关闭当前进程,重新打开一个新的进程。
运行结果:
以下为进程A,待输入1后会被关闭。
以下为进程B,进程A被关闭后,进程B将会被创建。
可以看到两个进程的PID不同,符合预期。