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;
}
Esempio n. 2
0
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;
}