UINT UpgradeMsi(HINSTANCE hInst, CDownloadUI *piDownloadUI, LPCSTR szAppTitle, LPCSTR szBase, LPCSTR szUpdate, ULONG ulMinVer) { char *szTempPath = 0; char *szUpdatePath = 0; char *szFilePart = 0; DWORD cchTempPath = 0; DWORD cchUpdatePath = 0; DWORD cchReturn = 0; DWORD dwLastError = 0; DWORD dwFileAttrib = 0; UINT uiRet = 0; HRESULT hr = S_OK; // generate the path to the MSI update file = szBase + szUpdate // note: szUpdate is a relative path cchTempPath = lstrlen(szBase) + lstrlen(szUpdate) + 2; // 1 for null terminator, 1 for back slash szTempPath = new char[cchTempPath]; if (!szTempPath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } memset((void*)szTempPath, 0x00, cchTempPath*sizeof(char)); // find 'setup.exe' in the path so we can remove it -- this is an already expanded path, that represents // our current running location. It includes our executable name -- we want to find that and get rid of it if (0 == GetFullPathName(szBase, cchTempPath, szTempPath, &szFilePart)) { uiRet = GetLastError(); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } if (szFilePart) *szFilePart = '\0'; hr = StringCchCat(szTempPath, cchTempPath, szUpdate); if (FAILED(hr)) { uiRet = HRESULT_CODE(hr); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } cchUpdatePath = 2*cchTempPath; szUpdatePath = new char[cchUpdatePath]; if (!szUpdatePath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } // normalize the path cchReturn = GetFullPathName(szTempPath, cchUpdatePath, szUpdatePath, &szFilePart); if (cchReturn > cchUpdatePath) { // try again, with larger buffer delete [] szUpdatePath; cchUpdatePath = cchReturn; szUpdatePath = new char[cchUpdatePath]; if (!szUpdatePath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } cchReturn = GetFullPathName(szTempPath, cchUpdatePath, szUpdatePath, &szFilePart); } if (0 == cchReturn) { uiRet = GetLastError(); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } // no download is necessary -- but we can check for the file's existence dwFileAttrib = GetFileAttributes(szUpdatePath); if (0xFFFFFFFF == dwFileAttrib) { // Update executable is missing PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_NOUPDATE, szUpdatePath); uiRet = ERROR_FILE_NOT_FOUND; goto CleanUp; } uiRet = ValidateUpdate(hInst, piDownloadUI, szAppTitle, szUpdatePath, szUpdatePath, ulMinVer); CleanUp: if (szTempPath) delete [] szTempPath; if (szUpdatePath) delete [] szUpdatePath; return uiRet; }
UINT UpgradeMsi( ISetupUI* pSetupUI, LPCTSTR szBase, LPCTSTR szUpdate, ULONG ulMinVer) { TCHAR *szTempPath = 0; TCHAR *szUpdatePath = 0; TCHAR *szFilePart = 0; DWORD cchTempPath = 0; DWORD cchUpdatePath = 0; DWORD cchReturn = 0; DWORD dwLastError = 0; DWORD dwFileAttrib = 0; UINT uiRet = 0; HRESULT hr = S_OK; // generate the path to the MSI update file = szBase + szUpdate // note: szUpdate is a relative path cchTempPath = lstrlen(szBase) + lstrlen(szUpdate) + 2; // 1 for null terminator, 1 for back slash szTempPath = new TCHAR[cchTempPath]; if (!szTempPath) { uiRet = ERROR_OUTOFMEMORY; pSetupUI->PostErrorMessageBox( uiRet, IDS_ERR_OUTOFMEM, MB_OK | MB_ICONERROR); goto CleanUp; } ::ZeroMemory(szTempPath, cchTempPath*sizeof(TCHAR)); // find 'setup.exe' in the path so we can remove it -- this is an already expanded path, that represents // our current running location. It includes our executable name -- we want to find that and get rid of it if (0 == GetFullPathName(szBase, cchTempPath, szTempPath, &szFilePart)) { uiRet = GetLastError(); CString str; str.FormatMessage(IDS_INVALID_PATH_FMT, szTempPath); pSetupUI->PostErrorMessageBox(uiRet, str, MB_OK | MB_ICONERROR); goto CleanUp; } if (szFilePart) { *szFilePart = '\0'; } hr = StringCchCat(szTempPath, cchTempPath, szUpdate); if (FAILED(hr)) { uiRet = HRESULT_CODE(hr); CString str; str.FormatMessage(IDS_INVALID_PATH_FMT, szTempPath); pSetupUI->PostErrorMessageBox(uiRet, str, MB_OK | MB_ICONERROR); goto CleanUp; } cchUpdatePath = 2*cchTempPath; szUpdatePath = new TCHAR[cchUpdatePath]; if (!szUpdatePath) { uiRet = ERROR_OUTOFMEMORY; pSetupUI->PostErrorMessageBox( uiRet, IDS_ERR_OUTOFMEM, MB_OK | MB_ICONERROR); goto CleanUp; } // normalize the path cchReturn = GetFullPathName( szTempPath, cchUpdatePath, szUpdatePath, &szFilePart); if (cchReturn > cchUpdatePath) { // try again, with larger buffer delete [] szUpdatePath; cchUpdatePath = cchReturn; szUpdatePath = new TCHAR[cchUpdatePath]; if (!szUpdatePath) { uiRet = ERROR_OUTOFMEMORY; pSetupUI->PostErrorMessageBox( uiRet, IDS_ERR_OUTOFMEM, MB_OK | MB_ICONERROR); goto CleanUp; } cchReturn = GetFullPathName( szTempPath, cchUpdatePath, szUpdatePath, &szFilePart); } if (0 == cchReturn) { uiRet = GetLastError(); CString str; str.FormatMessage(IDS_INVALID_PATH_FMT, szTempPath); pSetupUI->PostErrorMessageBox(uiRet, str, MB_OK | MB_ICONERROR); goto CleanUp; } // no download is necessary -- but we can check for the file's existence dwFileAttrib = GetFileAttributes(szUpdatePath); if (0xFFFFFFFF == dwFileAttrib) { uiRet = ERROR_FILE_NOT_FOUND; // Update executable is missing CString str; str.FormatMessage(IDS_NOUPDATE_FMT, szUpdatePath); pSetupUI->PostErrorMessageBox(uiRet, str, MB_OK | MB_ICONERROR); goto CleanUp; } pSetupUI->SetProgressBar(20); uiRet = ValidateUpdate( pSetupUI, szUpdatePath, szUpdatePath, ulMinVer); pSetupUI->SetProgressBar(100); CleanUp: if (szTempPath) delete [] szTempPath; if (szUpdatePath) delete [] szUpdatePath; return uiRet; }
UINT DownloadAndUpgradeMsi(HINSTANCE hInst, CDownloadUI *piDownloadUI, LPCSTR szAppTitle, LPCSTR szUpdateLocation, LPCSTR szUpdate, LPCSTR szModuleFile, ULONG ulMinVer) { char *szTempPath = 0; char *szUpdatePath = 0; char *szUpdateCacheFile = 0; const char *pch = 0; DWORD cchTempPath = 0; DWORD cchUpdatePath = 0; DWORD cchUpdateCacheFile = 0; DWORD dwLastError = 0; UINT uiRet = 0; HRESULT hr = 0; DWORD Status = ERROR_SUCCESS; char szDebugOutput[MAX_STR_LENGTH] = {0}; char szText[MAX_STR_CAPTION] = {0}; // generate the path to the update == UPDATELOCATION + szUpdate // note: szUpdate is a relative path cchTempPath = lstrlen(szUpdateLocation) + lstrlen(szUpdate) + 2; // 1 for slash, 1 for null szTempPath = new char[cchTempPath]; if (!szTempPath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } memset((void*)szTempPath, 0x0, cchTempPath*sizeof(char)); hr = StringCchCopy(szTempPath, cchTempPath, szUpdateLocation); if (FAILED(hr)) { uiRet = HRESULT_CODE(hr); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } // check for trailing slash on szUpdateLocation pch = szUpdateLocation + lstrlen(szUpdateLocation) + 1; // put at null terminator pch = CharPrev(szUpdateLocation, pch); if (*pch != '/') { hr = StringCchCat(szTempPath, cchTempPath, szUrlPathSep); if (FAILED(hr)) { uiRet = HRESULT_CODE(hr); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } } hr = StringCchCat(szTempPath, cchTempPath, szUpdate); if (FAILED(hr)) { uiRet = HRESULT_CODE(hr); PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); goto CleanUp; } // canonicalize the URL path cchUpdatePath = cchTempPath*2; szUpdatePath = new char[cchUpdatePath]; if (!szUpdatePath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } if (!InternetCanonicalizeUrl(szTempPath, szUpdatePath, &cchUpdatePath, 0)) { dwLastError = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == dwLastError) { // try again delete [] szUpdatePath; szUpdatePath = new char[cchUpdatePath]; if (!szUpdatePath) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } dwLastError = 0; // reset to success for 2nd attempt if (!InternetCanonicalizeUrl(szTempPath, szUpdatePath, &cchUpdatePath, 0)) dwLastError = GetLastError(); } } if (0 != dwLastError) { // error -- invalid path/Url PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_INVALID_PATH, szTempPath); uiRet = dwLastError; goto CleanUp; } DebugMsg("[Info] Downloading update package from --> %s\n", szUpdatePath); // set action text for download WIN::LoadString(hInst, IDS_DOWNLOADING_UPDATE, szText, MAX_STR_CAPTION); if (irmCancel == piDownloadUI->SetActionText(szText)) { ReportUserCancelled(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_INSTALL_USEREXIT; goto CleanUp; } // download the Update file so we can run it -- must be local to execute szUpdateCacheFile = new char[MAX_PATH]; cchUpdateCacheFile = MAX_PATH; if (!szUpdateCacheFile) { ReportErrorOutOfMemory(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_OUTOFMEMORY; goto CleanUp; } hr = WIN::URLDownloadToCacheFile(NULL, szUpdatePath, szUpdateCacheFile, cchUpdateCacheFile, 0, /* IBindStatusCallback = */ &CDownloadBindStatusCallback(piDownloadUI)); if (piDownloadUI->HasUserCanceled()) { ReportUserCancelled(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle); uiRet = ERROR_INSTALL_USEREXIT; goto CleanUp; } if (FAILED(hr)) { // error during download -- probably because file not found (or lost connection) PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_NOUPDATE, szUpdatePath); uiRet = ERROR_FILE_NOT_FOUND; goto CleanUp; } // // Perform trust check on MSI. Note, this must be done in a separate process. // This is because MSI 2.0 and higher register sip callbacks for verifying // digital signatures on msi files. At this point, it is quite likely that // the SIP callbacks have not been registered. So we don't want to load // wintrust.dll into this process's image yet, otherwise it will remain unaware // of the sip callbacks registered by WindowsInstaller-KB884016-x86.exe and will // fail later when it tries to verify the signature on the msi file downloaded // from the web. // Status = ExecuteVerifyUpdate(szModuleFile, szUpdateCacheFile); if (TRUST_E_PROVIDER_UNKNOWN == Status) { PostError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_NO_WINTRUST); uiRet = ERROR_CALL_NOT_IMPLEMENTED; goto CleanUp; } else if (ERROR_SUCCESS != Status) { PostFormattedError(hInst, piDownloadUI->GetCurrentWindow(), szAppTitle, IDS_UNTRUSTED, szUpdateCacheFile); uiRet = HRESULT_CODE(TRUST_E_SUBJECT_NOT_TRUSTED); goto CleanUp; } // continue other validations uiRet = ValidateUpdate(hInst, piDownloadUI, szAppTitle, szUpdateCacheFile, szModuleFile, ulMinVer); CleanUp: if (szTempPath) delete [] szTempPath; if (szUpdatePath) delete [] szUpdatePath; if (szUpdateCacheFile) { WIN::DeleteUrlCacheEntry(szUpdateCacheFile); delete [] szUpdateCacheFile; } return uiRet; }