php 在线升级程序,win32程序在线自动升级(更新)的方法

本文详细介绍了如何设计和实现一个自动更新程序,包括主程序和更新程序的交互,以及如何通过比较版本号和下载更新文件来实现无缝升级。在更新过程中,更新程序会以临时文件的方式运行,避免自身被覆盖,同时能够根据接收到的参数结束旧进程并启动新版本。整个流程确保了更新的完整性和用户体验。
摘要由CSDN通过智能技术生成

程序使用过程肯定会跟进修改一些bug,添加一些新功能等这个时候就要有在线更新功能啦。具体要求就是最常见的更新下载然后自动重新启动,

自动更新方案

实现这种方法至少要两个程序一个主程序(main.exe)一个更新程序(Update.exe)

主程序启动后另起一个新的线程调用Update.exe来检查软件并更新,单单这样也不可以,因为Update.exe更新时候是占用的状态,是覆盖不了的。

Update.exe启动的时候先检查自己的文件名字是不是UpdateTem.exe,如果不是的话就把自己复制一份,复制到当前目录中的这个路径 Update/UpdateTem.exe 当前程序结束,  然后运行这个临时文件临时文件运行的时候也会检查当前的文件名字,这一次文件名字就等于UpdateTem.exe啦。就正常运行更新程序,把更新文件zip包直接解压到上级目录覆盖就可以啦

更新程序要接收的参数字符串如下update.exe 1.0.0  url   pid

参数:

1.0.0 当前程序的版本号

url 检查软件版本信息地址

pid 主程序启动后的进程pid,如果有更新的话要用pid结束掉原来的主进程,然后由更新程序重启启动

检查更新格式

返回一个json的格式字符串<?php

header('Content-type: application/json; charset=utf-8'); //json

$descr = <<

v0.2.0

修复反馈的bug

添加一些新功能

新版本的一些特性

eot;

$jsondata = [

"lastversion" => "0.2.0", //版本号

"downloadurl" => "http://www.xxx.com/update.zip", //新版本压缩包

"descr"       => $descr, //新版本的一些描述

"run"         => "HeMei_u_d.exe", //更新成功后执行的当前目录的程序,如果为空就什么也不启动

"autoupdate"  => false,

];

echo json_encode($jsondata);

Update升级程序部分代码

一般情况下程序退出都是0,我们可以给更新程序加一些自定义的退出码,方便主程序实现更复杂的功能

//更新程序的退出码,

//0没有新版本,

//1有新版本并且已经下载替换重启启动,

//2有新版本但是取消下载啦

//3出现错误

把判断是不是运行的临时的更新文件//取当前执行模块的全路径,如果此模块是被其它程序调用的,返回的路径还是这个程序的路径

::GetModuleFileName(NULL, MainWnd::s_curPath, MAX_PATH);

//从路径中移除文件名

PathRemoveFileSpec(MainWnd::s_curPath);

TCHAR curFileName[MAX_PATH];

//取当前可执行文件的全路径

::GetModuleFileName(NULL, curFileName, MAX_PATH);

TCHAR* fname = ::PathFindFileName(curFileName);//取文件名

//临时的更新文件名

TCHAR temFileName[] = _T("UpdateTem.exe");

if (_tcscmp(fname, temFileName) != 0) {

TCHAR opath[MAX_PATH] = { 0 }, npath[MAX_PATH] = { 0 }, updatepath[MAX_PATH] = { 0 };

_stprintf(updatepath, _T("%s\\Update\\"), MainWnd::s_curPath);

if (!PathIsDirectory(updatepath))

{

if (!CreateDirectory(updatepath, 0))

return false;

}

_stprintf(opath, _T("%s\\Update.exe"), MainWnd::s_curPath);

_stprintf(npath, _T("%s\\Update\\%s"), MainWnd::s_curPath, temFileName);

//把自己copy到二级目录运行二级目录中的文件

CopyFile(opath, npath, false);

*opath = { 0 }, *npath = { 0 };

_stprintf(opath, _T("%s\\DuiLib_u_d.dll"), MainWnd::s_curPath);

_stprintf(npath, _T("%s\\Update\\DuiLib_u_d.dll"), MainWnd::s_curPath);

//把自己copy到二级目录运行二级目录中的文件

CopyFile(opath, npath, false);

TCHAR strFilePath[MAX_PATH] = { 0 };

_stprintf_s(strFilePath, _T("\"%s%s\""), updatepath, temFileName);

ShellExecute(NULL, _T("open"), strFilePath, lpCmdLine, _T(""), SW_HIDE);

return 0;

}

//运行到这里的时候update.exe已经被放进二级目录啦,所以当前目录路径要返回一级目录

TCHAR* pp = _tcsrchr(MainWnd::s_curPath, _T('\\'));

if (pp) {

*pp = 0;

}

解析传进来的参数//命令行接收格式为 update.exe  1.0.0 url  pid

LPTSTR *szArgList;

int argCount;

szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);

#ifdef _DEBUG

//argCount = 4;

//szArgList[0] = L"update.exe";

//szArgList[1] = L"0.1.0";

//szArgList[2] = L"http://crm369.hemeids.com:8888/CheckUpdate.php";

//szArgList[3] = L"0";

#endif // DEBUG

if (szArgList == NULL) {

MessageBox(NULL, L"没有参数传进来直接退出", L"提示", 0);

return 0;

}

if (argCount 

MessageBox(NULL, L"参数格式不正确", L"提示", 0);

return 0;

}

检查对比新版本号

启动时由上面代码解析出传过来的版本号,和从url中取过来的版本号tstring serverVersion = L"0.2.0";

tstring curVersion = L"0.0.1";

//对比两个版本的新旧

const TCHAR * split = L".";

const int verlen = 3;

//两个版本的数字数组

int version1[verlen] = { 0 }, version2[verlen] = { 0 };

TCHAR * p;

p = _tcstok((TCHAR*)curVersion.c_str(), split);

int i = 0;

while (p != NULL) {

int nums = _ttoi(p);

version1[i++] = nums;

p = _tcstok(NULL, split);

if (i > verlen)break;

}

p = _tcstok((TCHAR*)curVersion.c_str(), split);

i = 0;

while (p != NULL) {

int nums = _ttoi(p);

version2[i++] = nums;

p = _tcstok(NULL, split);

if (i > verlen)break;

}

bool isUpdate = false;

for (int j = 0;j <= verlen;j++)

{

if (version2[j] > version1[j]) {

isUpdate = true;

break;

}

}

//没有更新就什么也不做直接返回

if (!isUpdate) {

return 0;

}

//如果有更新就在下面下载并且替换文件....

//最后根据自己的处理结果返回对应的数字

return 1;

用Pid关闭主程序//更新前要终止之前的程序

//================TerminateProcess================//根据进程ID强杀

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, m_pVersionInfo->parentPid);

if (hProcess)

{

TerminateProcess(hProcess, 4);

CloseHandle(hProcess);

}

主程序检查更新代码

检查更新的代码要放到一个线程里运行,只不然会卡界面

传参数运行更新程序,并取返回的退出码相应的处理static DWORD WINAPI CheckUpdate(LPVOID lpParameter);

DWORD MainWnd::CheckUpdate(LPVOID lpParameter)

{

//检查更新程序

DWORD pid = GetCurrentProcessId();

TCHAR cmd[MAX_PATH] = { 0 };

_stprintf(cmd, L"%sUpdate.exe %s %s %d",L".\\", L"0.0.1", _T("http://www.xxx.com/CheckUpdate.php"), pid);

STARTUPINFO StartInfo;

PROCESS_INFORMATION procStruct;

memset(&StartInfo, 0, sizeof(STARTUPINFO));

StartInfo.cb = sizeof(STARTUPINFO);

BOOL working = ::CreateProcess(NULL, cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartInfo, &procStruct);

if (working == 0)

{

DWORD error = GetLastError();

MessageBox(NULL, L"启动检查更新出错", L"提示", 0);

return 0;

}

WaitForSingleObject(procStruct.hProcess, INFINITE);

unsigned long Result;

GetExitCodeProcess(procStruct.hProcess, &Result);

if (Result == 1) {

//新版本已经更新覆盖需要重启,这个进程直接退出

return 0;

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值