首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

基於 Web 的程式版本檢查實作:FTP + WinInet 輕量級自動更新方案

     編輯:關於VC++

前言:使用者體驗優先

避免啟動時強制彈出「是否更新」對話框干擾使用者。採用「靜默檢查 → 發現新版本顯示超連結 → 使用者自主決定」的友善模式。

一、核心思路

  1. 將版本資訊 (如 4,3,0,0) 以文字檔 (version.txt) 放置 FTP 伺服器。
  2. 應用程式啟動時,透過 WinInet API 讀取遠端版本號。
  3. 與本地 VS_VERSION_INFO 資源比對,新版本時於介面顯示「更新版本 x.xx」連結。
  4. 點擊連結可開啟下載頁或啟動更新程式。

二、WinInet FTP 讀取固定流程

HINTERNET hInternet = InternetOpen(...);
HINTERNET hFtp = InternetConnect(hInternet, server, INTERNET_DEFAULT_FTP_PORT, user, pass, INTERNET_SERVICE_FTP, 0, 0);
HINTERNET hFile = FtpOpenFile(hFtp, "version.txt", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
InternetReadFile(hFile, buffer, size, &dwRead);

三、封裝類別 CWebVersion

3.1 類別宣告

class CWebVersion {
protected:
    enum { BUFSIZE = 64 };
    LPCTSTR m_lpServer;
    DWORD m_dwError;
    TCHAR m_errInfo[256];
    TCHAR m_version[BUFSIZE];
    void SaveErrorInfo();
public:
    DWORD dwVersionMS, dwVersionLS; // 64-bit 版本號拆為高低 32 位
    CWebVersion(LPCTSTR server) : m_lpServer(server) {}
    static BOOL Online();                     // 檢查網路連線
    BOOL ReadVersion(LPCTSTR file, LPCSTR user, LPCSTR pass);
    LPCTSTR GetVersionText() { return m_version; }
    DWORD GetError() { return m_dwError; }
    LPCTSTR GetExtendedErrorInfo() { return m_errInfo; }
};

3.2 關鍵實作

BOOL CWebVersion::Online() {
    DWORD dwState = 0, dwSize = sizeof(DWORD);
    return InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize)
        && (dwState & INTERNET_STATE_CONNECTED);
}

BOOL CWebVersion::ReadVersion(LPCTSTR lpFileName, LPCSTR user, LPCSTR pass) {
    CInternetHandle hInternet, hFtpSession, hFtpFile;
    m_version[0] = 0; m_dwError = 0; m_errInfo[0] = 0;
    DWORD nRead = 0;

    hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet) {
        hFtpSession = InternetConnect(hInternet, m_lpServer, INTERNET_DEFAULT_FTP_PORT,
            user, pass, INTERNET_SERVICE_FTP, 0, NULL);
        if (hFtpSession) {
            hFtpFile = FtpOpenFile(hFtpSession, lpFileName, GENERIC_READ,
                FTP_TRANSFER_TYPE_ASCII, NULL);
            if (hFtpFile) {
                InternetReadFile(hFtpFile, m_version, BUFSIZE, &nRead);
                if (nRead > 0) {
                    m_version[nRead] = 0;
                    int Mhi, Mlo, mhi, mlo;
                    _stscanf(m_version, "%x,%x,%x,%x", &Mhi, &Mlo, &mhi, &mlo);
                    dwVersionMS = MAKELONG(Mlo, Mhi);
                    dwVersionLS = MAKELONG(mlo, mhi);
                    return TRUE;
                }
            }
        }
    }
    m_dwError = GetLastError();
    if (m_dwError == ERROR_INTERNET_EXTENDED_ERROR) {
        DWORD dwErr, len = _countof(m_errInfo);
        InternetGetLastResponseInfo(&dwErr, m_errInfo, &len);
    }
    return FALSE;
}

3.3 RAII 封裝 CInternetHandle

class CInternetHandle {
    HINTERNET m_handle;
public:
    CInternetHandle() : m_handle(NULL) {}
    CInternetHandle(HINTERNET h) : m_handle(h) {}
    ~CInternetHandle() { Close(); }
    void Close() { if (m_handle) { InternetCloseHandle(m_handle); m_handle = NULL; } }
    CInternetHandle& operator=(HINTERNET h) { ASSERT(m_handle==NULL); m_handle=h; return *this; }
    operator HINTERNET() { return m_handle; }
};

解決 InternetCloseHandle 清除錯誤碼導致 GetLastError 失效的問題,簡化錯誤處理流程。

四、為何不直接用 MFC 的 CInternetSession?

  • 輕量級需求不值得引入整個 MFC。
  • 非 MFC 專案 (Console、Win32 SDK) 亦可直接使用。
  • 避免部署最新 MFC DLL 的相容性風險。

五、對話方塊專案整合範例

5.1 InitInstance 中背景檢查

if (CWebVersion::Online()) {
    CWebVersion ver(_T("pub.chinafsdu.net"));
    if (ver.ReadVersion(_T("version.txt"), _T("pub"), _T("pub")))
        m_dwNewVersion = ver.dwVersionMS; // 僅比較高 32 位示範
}

5.2 OnInitDialog 顯示/隱藏更新連結

CMyVersionInfo vi; // 取得本地 VS_VERSION_INFO
if (m_dwNewVersion && vi.dwProductVersionMS < m_dwNewVersion) {
    CString s; s.Format(_T("更新版本 %d.%02d"), HIWORD(m_dwNewVersion), LOWORD(m_dwNewVersion));
    m_wndVerChkLink.SetWindowText(s);
} else {
    m_wndVerChkLink.ShowWindow(SW_HIDE);
}

5.3 效能考量

FTP 下載 10 字節通常極快,但受伺服器位置/負載影響可能有明顯延遲。建議放入背景執行緒執行 ReadVersion,避免阻塞 UI 啟動。

六、本地版本資源讀取輔助類 CMyVersionInfo

封裝 GetFileVersionInfo/VerQueryValue 解析 VS_VERSION_INFO 取得 dwProductVersionMS/LS,程式碼見原文附件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved