|  | 
 
| VC++MFC自动更新程序中实现文件替换,可采用以下三种主流方案 ************方案1:批处理脚本替换(推荐)************
 通过生成临时批处理脚本实现异步替换,避免文件占用冲突 
 ************方案2:独立更新程序************复制代码
void CAutoUpdater::CreateReplaceScript(const CString& strTargetPath) {
    CString strBatPath = GetTempPath() + _T("replace.bat");
    HANDLE hFile = CreateFile(strBatPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
    CString strCmd;
    strCmd.Format(_T("@echo off\r\n")
                 _T("timeout /t 3 /nobreak >nul\r\n")  // 等待主程序退出
                 _T("move /y "%s" "%s"\r\n")       // 替换文件
                 _T("start "" "%s"\r\n")          // 启动新程序
                 _T("del "%%~f0"\r\n"),             // 自删除脚本
                 m_strTempPath, strTargetPath, strTargetPath);
    
    DWORD dwWritten;
    WriteFile(hFile, strCmd, strCmd.GetLength() * sizeof(TCHAR), &dwWritten, NULL);
    CloseHandle(hFile);
    
    ShellExecute(NULL, _T("open"), strBatPath, NULL, NULL, SW_HIDE);
}
分离更新逻辑到独立进程,通过进程间通信控制替换流程: 以下是独立更新程序Updater.exe的完整实现方案,包含进程通信和文件替换逻辑主程序检测到更新后启动Updater.exe主程序退出后,Updater.exe完成文件替换Updater.exe启动新版本主程序后自退出
 Updater.h
 
 Updater.cpp复制代码
#pragma once
#include <vector>
class CUpdater {
public:
    BOOL Init(int argc, TCHAR* argv[]);
    BOOL PerformUpdate();
private:
    BOOL WaitForProcessExit(DWORD dwPID);
    BOOL ReplaceFiles();
    BOOL StartNewVersion();
    
    CString m_strMainExePath;
    CString m_strUpdateDir;
    DWORD m_dwMainPID;
    std::vector<CString> m_vecReplaceFiles;
};
 UpdaterApp.cpp复制代码 "stdafx.h"
#include "Updater.h"
#include <tlhelp32.h>
BOOL CUpdater::Init(int argc, TCHAR* argv[]) {
    if(argc < 4) return FALSE;
    
    m_dwMainPID = _ttoi(argv[1]);
    m_strMainExePath = argv[2];
    m_strUpdateDir = argv[3];
    
    WIN32_FIND_DATA fd;
    HANDLE hFind = FindFirstFile(m_strUpdateDir + _T("\\*.*"), &fd);
    while(hFind != INVALID_HANDLE_VALUE) {
        if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            m_vecReplaceFiles.push_back(fd.cFileName);
        }
        if(!FindNextFile(hFind, &fd)) break;
    }
    FindClose(hFind);
    
    return !m_vecReplaceFiles.empty();
}
BOOL CUpdater::WaitForProcessExit(DWORD dwPID) {
    HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, dwPID);
    if(hProcess) {
        WaitForSingleObject(hProcess, 10000); // 最多等待10秒
        CloseHandle(hProcess);
    }
    return TRUE;
}
BOOL CUpdater::ReplaceFiles() {
    for(auto& file : m_vecReplaceFiles) {
        CString src = m_strUpdateDir + _T("\") + file;
        CString dest = m_strMainExePath.Left(m_strMainExePath.ReverseFind('\\') + 1) + file;
        
        if(!MoveFileEx(src, dest, MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH)) {
            return FALSE;
        }
    }
    return TRUE;
}
BOOL CUpdater::StartNewVersion() {
    SHELLEXECUTEINFO sei = {0};
    sei.cbSize = sizeof(sei);
    sei.lpFile = m_strMainExePath;
    sei.nShow = SW_SHOW;
    return ShellExecuteEx(&sei);
}
BOOL CUpdater::PerformUpdate() {
    return WaitForProcessExit(m_dwMainPID) && 
           ReplaceFiles() && 
           StartNewVersion();
}
 复制代码 "stdafx.h"
#include "Updater.h"
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
    CUpdater updater;
    if(updater.Init(__argc, __targv)) {
        if(updater.PerformUpdate()) {
            return 0;
        }
    }
    return 1;
}
代码说明: 主程序调用方式:Updater.exe [主进程ID] [主程序路径] [更新文件目录]使用WaitForSingleObject确保主程序退出采用MOVEFILE_WRITE_THROUGH确保文件完全替换更新完成后自动启动新版本
 使用流程: 主程序下载更新包到临时目录启动Updater.exe并传入自身PID和路径主程序立即退出Updater.exe完成文件替换后启动新版本
 注意事项: 需要管理员权限才能替换系统目录文件建议添加文件校验逻辑确保完整性生产环境应使用数字签名验证更新包
 ************方案3:Windows卷影复制************
 利用VSS服务实现文件热替换 复制代码BOOL ReplaceWithShadowCopy(LPCTSTR lpszSrc, LPCTSTR lpszDest) {
    // 需要链接VSSAPI.LIB
    IVssBackupComponents* pVss = NULL;
    CoCreateInstance(CLSID_VssBackupComponents, NULL, CLSCTX_ALL, 
                    IID_IVssBackupComponents, (void**)&pVss);
    pVss->InitializeForBackup();
    pVss->SetContext(VSS_CTX_APP_ROLLBACK);
    
    // 创建卷影副本并执行文件替换...
}
 
 关键注意事项
 权限处理:需请求管理员权限才能替换Program Files目录文件版本回滚:应保留旧版本备份以便恢复文件校验:替换前需验证MD5/SHA校验值日志记录:记录替换操作结果便于故障排查
 实际项目中推荐方案1+方案2组合使用,通过批处理完成简单替换,复杂场景使用独立更新程序 
 
 
 | 
 |