#include "wsdueng.h" HINSTANCE g_hinst; CDynamicUpdate *g_pDynamicUpdate = NULL; DWORD WaitAndPumpMessages(DWORD nCount, LPHANDLE pHandles, DWORD dwWakeMask); BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved) { if (dwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hInstance); g_hinst = hInstance; } else if (dwReason == DLL_PROCESS_DETACH) { ; } return TRUE; } // Required function to be able to link CDMLIB.. HMODULE GetModule() { return g_hinst; } // -------------------------------------------------------------------------- // Function Name: SetEstimatedDownloadSpeed // Function Description: Sets the Download speed used for download time estimates // // Function Returns: // Nothing // void WINAPI SetEstimatedDownloadSpeed(DWORD dwBytesPerSecond) { if (NULL != g_pDynamicUpdate) g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond = dwBytesPerSecond; } // -------------------------------------------------------------------------- // Function Name: DuInitializeA // Function Description: Initializes the DynamicUpdate class and converts the OSVERSIONINFO information into a Platform ID // // Function Returns: // INVALID_HANDLE_VALUE if it fails // HANDLE value of 1 if it succeeds // // NOTE: The use of a HANDLE could allow us to return the address of the DynamicUpdate Object, which was originally intended, but it seemed simpler // to just use a global.. HANDLE WINAPI DuInitializeA(IN LPCSTR pszBasePath, IN LPCSTR pszTempPath, POSVERSIONINFOEXA posviTargetOS, IN LPCSTR pszTargetArch, IN LCID lcidTargetLocale, IN BOOL fUnattend, IN BOOL fUpgrade, IN PWINNT32QUERY pfnWinnt32QueryCallback) { LOG_block("DuInitializeA in DuEng"); // parameter validation // RogerJ, October 5th, 2000 if (!pfnWinnt32QueryCallback) { LOG_error("Callback function pointer invalid"); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } // DONE RogerJ // parse the OSVERSIONINFO struct for the platform ID int iPlatformID = 0; // The TargetOS Platform ID is based on a couple of things. // The Whister Platform ID is the OSVERSIONINFOEX structure with the fields dwMajorVersion and dwMinorVersion set to 5.1 // The other identifier in the platform ID is whether its i386 or ia64 (64bit) .. This is defined in the pszTargetArch String if (5 == posviTargetOS->dwMajorVersion) { if (1 == posviTargetOS->dwMinorVersion) { // Whistler if (NULL != StrStrI(pszTargetArch, "i386")) { iPlatformID = 18; // Whistler x86 (normal) } else if (NULL != StrStrI(pszTargetArch, "ia64")) { iPlatformID = 19; // Whistler ia64 (64bit) } } else if (2 == posviTargetOS->dwMinorVersion) { // Whistler if (NULL != StrStrI(pszTargetArch, "i386")) { iPlatformID = 18; // Whistler x86 (normal) } else if (NULL != StrStrI(pszTargetArch, "ia64")) { iPlatformID = 19; // Whistler ia64 (64bit) } } } if (0 == iPlatformID) { // No known Platform ID for DynamicUpdate was found.. Return Error return INVALID_HANDLE_VALUE; } WORD wPlatformSKU = posviTargetOS->wSuiteMask; if (g_pDynamicUpdate) { // a former call to this function has already initialized an instance of CDynamicUpdate class delete g_pDynamicUpdate; g_pDynamicUpdate = NULL; } g_pDynamicUpdate = new CDynamicUpdate(iPlatformID, lcidTargetLocale, wPlatformSKU, pszTempPath, pszBasePath, pfnWinnt32QueryCallback, posviTargetOS); if (NULL == g_pDynamicUpdate) { return INVALID_HANDLE_VALUE; } return (HANDLE)1; } // -------------------------------------------------------------------------- // Function Name: DuDoDetection // Function Description: Searches the Catalogs on the WU Site to find Updates for setup // // Function Returns: // FALSE if there are no items OR there is an error.. Use GetLastError() for more information. // TRUE if it succeeds and there are items to download. // // Comment: If return value is FALSE and GetLastError return ERROR_NO_MORE_ITEMS there are no items to download. // // Modified by RogerJ October 6th, 2000 // --- Added Driver Detection BOOL WINAPI DuDoDetection(IN HANDLE hConnection, OUT PDWORD pdwEstimatedTime, OUT PDWORD pdwEstimatedSize) { LOG_block("DuDoDetection in DuEng"); DWORD dwRetSetup, dwRetDriver; dwRetSetup = dwRetDriver = 0; if (NULL == g_pDynamicUpdate) return FALSE; g_pDynamicUpdate->ClearDownloadItemList(); dwRetSetup = g_pDynamicUpdate->DoSetupUpdateDetection(); if (ERROR_SUCCESS != dwRetSetup) { LOG_error("Failed to get setup update item! --- %d", dwRetSetup); g_pDynamicUpdate->PingBack(DU_PINGBACK_SETUPDETECTIONFAILED, 0, NULL, FALSE); } // do driver detection here if (!g_pDynamicUpdate->DoDriverDetection() || !g_pDynamicUpdate->DoWindowsUpdateDriverDetection()) { LOG_error("Failed to detect driver!"); dwRetDriver = GetLastError(); g_pDynamicUpdate->PingBack(DU_PINGBACK_DRIVERDETECTIONFAILED, 0, NULL, FALSE); } if (dwRetSetup && dwRetDriver) { LOG_error("Both Setup item and Driver detection failed"); return FALSE; } if (g_pDynamicUpdate->m_dwDownloadItemCount > 0) { g_pDynamicUpdate->UpdateDownloadItemSize(); *pdwEstimatedSize = g_pDynamicUpdate->m_dwTotalDownloadSize; // size in bytes // Time Estimate is based on roughly how long it took us to download the data files. if (0 == g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond) g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond = 2048; // default to 120k per minute, (2048 bytes per second). *pdwEstimatedTime = g_pDynamicUpdate->m_dwTotalDownloadSize / g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond; // number of seconds if (*pdwEstimatedTime == 0) *pdwEstimatedTime = 1; // at least one second if (dwRetSetup) SetLastError(dwRetSetup); if (dwRetDriver) SetLastError(dwRetDriver); return TRUE; } else { // initialize the size and time for setup *pdwEstimatedTime = 1; *pdwEstimatedSize = 0; // At this point there was no error, but we have no items to download, SetLastError(ERROR_NO_MORE_ITEMS); return TRUE; } } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- BOOL WINAPI DuBeginDownload(IN HANDLE hConnection, IN HWND hwndNotify) { if ((NULL == g_pDynamicUpdate) || (NULL == hwndNotify)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (0 == g_pDynamicUpdate->m_dwDownloadItemCount) { SetLastError(ERROR_NO_MORE_ITEMS); PostMessage(hwndNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_SUCCESS, (LPARAM) NULL); return TRUE; } g_pDynamicUpdate->SetCallbackHWND(hwndNotify); g_pDynamicUpdate->SetAbortDownload(FALSE); if (ERROR_SUCCESS != g_pDynamicUpdate->DownloadFilesAsync()) { return FALSE; } return TRUE; // download has been started } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- void WINAPI DuAbortDownload(IN HANDLE hConnection) { if (NULL == g_pDynamicUpdate) return; g_pDynamicUpdate->SetAbortDownload(TRUE); return; } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- void WINAPI DuUninitialize(IN HANDLE hConnection) { if (NULL == g_pDynamicUpdate) return; // We want to hold up the Uninitialize process until any other Threads // specifically the Download Thread. We are going to wait on the DownloadThreadProc // thread handle if it exists. Once the thread finishes, the wait proc will exit // and we can continue. if (NULL != g_pDynamicUpdate->m_hDownloadThreadProc) WaitAndPumpMessages(1, &g_pDynamicUpdate->m_hDownloadThreadProc, QS_ALLINPUT); delete g_pDynamicUpdate; g_pDynamicUpdate = NULL; LOG_close(); return; } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- CDynamicUpdate::CDynamicUpdate(int iPlatformID, LCID lcidLocaleID, WORD wPlatformSKU, LPCSTR pszTempPath, LPCSTR pszDownloadPath, PWINNT32QUERY pfnWinnt32QueryCallback, POSVERSIONINFOEXA pVersionInfo) : m_iPlatformID(iPlatformID), m_lcidLocaleID(lcidLocaleID), m_wPlatformSKU(wPlatformSKU), m_hwndClientNotify(NULL), m_pDownloadItemList(NULL), m_dwDownloadItemCount(0), m_dwTotalDownloadSize(0), m_dwCurrentBytesDownloaded(0), m_hInternet(NULL), m_hConnect(NULL), m_hOpenRequest(NULL), m_pV3(NULL), m_fAbortDownload(FALSE), m_dwLastPercentComplete(0), m_dwDownloadSpeedInBytesPerSecond(0), m_hDownloadThreadProc(NULL), m_pfnWinNT32Query(pfnWinnt32QueryCallback) { (void)FixUpV3LocaleID(); // BUG: 435184 - Map 0c0a to 040a for V3 purposes if (NULL != pszTempPath) { lstrcpy(m_szTempPath, pszTempPath); } if (NULL != pszDownloadPath) { lstrcpy(m_szDownloadPath, pszDownloadPath); } lstrcpy(m_szCurrentConnectedServer, ""); // initialize to null. CopyMemory((PVOID)&m_VersionInfo, (PVOID)pVersionInfo, sizeof(OSVERSIONINFOEXA)); InitializeCriticalSection(&m_cs); InitializeCriticalSection(&m_csDownload); // m_hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES); } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- CDynamicUpdate::~CDynamicUpdate() { ClearDownloadItemList(); // free up any memory in the download list m_arrayHardwareId.RemoveAll(); if (m_pV3) delete m_pV3; m_pV3 = NULL; DeleteCriticalSection(&m_cs); DeleteCriticalSection(&m_csDownload); SafeInternetCloseHandle(m_hOpenRequest); SafeInternetCloseHandle(m_hConnect); SafeInternetCloseHandle(m_hInternet); SafeCloseHandle(m_hDownloadThreadProc); } LPSTR CDynamicUpdate::DuUrlCombine(LPSTR pszDest, LPCSTR pszBase, LPCSTR pszAdd) { if ((NULL == pszDest) || (NULL == pszBase) || (NULL == pszAdd)) { return NULL; } lstrcpy(pszDest, pszBase); int iLen = lstrlen(pszDest); if ('/' == pszDest[iLen - 1]) { // already has a trailing slash, check the 'add' string for a preceding slash if ('/' == *pszAdd) { // has a preceding slash, skip it. lstrcat(pszDest, pszAdd + 1); } else { lstrcat(pszDest, pszAdd); } } else { // no trailing slash, check the add string for a preceding slash if ('/' == *pszAdd) { // has a preceding slash, Add Normally lstrcat(pszDest, pszAdd); } else { lstrcat(pszDest, "/"); lstrcat(pszDest, pszAdd); } } return pszDest; } LPCSTR CDynamicUpdate::GetDuDownloadPath() { return m_szDownloadPath; } LPCSTR CDynamicUpdate::GetDuServerUrl() { return m_szServerUrl; } LPCSTR CDynamicUpdate::GetDuTempPath() { return m_szTempPath; } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- DWORD CDynamicUpdate::DoSetupUpdateDetection() { if (NULL == m_pV3) { m_pV3 = new CV31Server(this); if (NULL == m_pV3) { return ERROR_NOT_ENOUGH_MEMORY; } } if (!m_pV3->ReadIdentInfo()) { return GetLastError(); } if (!m_pV3->GetCatalogPUIDs()) { return GetLastError(); } if (!m_pV3->GetCatalogs()) { // there was an error reading the catalogs return GetLastError(); } if (!m_pV3->ReadCatalogINI()) { return GetLastError(); } if (!m_pV3->UpdateDownloadItemList(m_VersionInfo)) { // there was an error parsing the catalogs and creating the download list. return GetLastError(); } return ERROR_SUCCESS; } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- void CDynamicUpdate::AddDownloadItemToList(DOWNLOADITEM *pDownloadItem) { LOG_block("CDynamicUpdate::AddDownloadItemToList"); if (NULL == pDownloadItem) { return; } if (NULL == m_pDownloadItemList) // no drivers in list yet { m_pDownloadItemList = pDownloadItem; } else { // add to the end of the list DOWNLOADITEM *pCurrent = m_pDownloadItemList; while (NULL != pCurrent->pNext) { pCurrent = pCurrent->pNext; } pCurrent->pNext = pDownloadItem; pDownloadItem->pPrev = pCurrent; } m_dwDownloadItemCount++; LOG_out("Item added, %d cab(s), first cab ---\"%s\"", pDownloadItem->iNumberOfCabs, pDownloadItem->mszFileList); } // -------------------------------------------------------------------------- // // // // // // // -------------------------------------------------------------------------- void CDynamicUpdate::RemoveDownloadItemFromList(DOWNLOADITEM *pDownloadItem) { if (NULL == pDownloadItem) { return; } if (NULL == m_pDownloadItemList) { return; } DOWNLOADITEM *pCurrent = m_pDownloadItemList; while (NULL != pCurrent) { if (pCurrent == pDownloadItem) { break; } pCurrent = pCurrent->pNext; } if ((NULL == pCurrent) || (pCurrent != pDownloadItem)) { return; // unexpected } if (NULL == pCurrent->pPrev) // first item in list { if (NULL == pCurrent->pNext) // only item in list { m_pDownloadItemList = NULL; m_dwDownloadItemCount = 0; } else { pCurrent->pNext->pPrev = NULL; // next job becomes first m_pDownloadItemList = pCurrent->pNext; m_dwDownloadItemCount--; } } else { pCurrent->pPrev->pNext = pCurrent->pNext; if (NULL != pCurrent->pNext) { pCurrent->pNext->pPrev = pCurrent->pPrev; } } } void CDynamicUpdate::SetCallbackHWND(HWND hwnd) { m_hwndClientNotify = hwnd; } void CDynamicUpdate::SetAbortDownload(BOOL fAbort) { EnterCriticalSection(&m_cs); m_fAbortDownload = fAbort; LeaveCriticalSection(&m_cs); } void CDynamicUpdate::UpdateDownloadItemSize() { m_dwTotalDownloadSize = 0; DOWNLOADITEM *pCurrent = m_pDownloadItemList; while (pCurrent) { m_dwTotalDownloadSize += pCurrent->dwTotalFileSize; pCurrent = pCurrent->pNext; } } void CDynamicUpdate::ClearDownloadItemList() { EnterCriticalSection(&m_csDownload); DOWNLOADITEM *pCurrent = m_pDownloadItemList; DOWNLOADITEM *pNext; while (pCurrent) { pNext = pCurrent->pNext; SafeGlobalFree(pCurrent); pCurrent = pNext; } m_pDownloadItemList = NULL; m_dwDownloadItemCount = 0; LeaveCriticalSection(&m_csDownload); } void CDynamicUpdate::EnterDownloadListCriticalSection() { EnterCriticalSection(&m_csDownload); } void CDynamicUpdate::LeaveDownloadListCriticalSection() { LeaveCriticalSection(&m_csDownload); } void CDynamicUpdate::FixUpV3LocaleID() { // Some XP Locale ID's map to a different Locale ID in V3 Terms // First Example was a new Spanish (Modern) Locale ID (0c0a) // which in V3 was (040a). For the V3 period we will fix up // any specific LCID's until IU handles this. switch (m_lcidLocaleID) { case 3082: // 0c0a = Spanish (Modern) { m_lcidLocaleID = 1034; // 040a break; } default: { // do nothing. } } return; }; DWORD WaitAndPumpMessages(DWORD nCount, LPHANDLE pHandles, DWORD dwWakeMask) { DWORD dwWaitResult; MSG msg; while (TRUE) { dwWaitResult = MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 1000, dwWakeMask); if (dwWaitResult <= WAIT_OBJECT_0 + nCount - 1) { return dwWaitResult; } if (WAIT_OBJECT_0 + nCount == dwWaitResult) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } return dwWaitResult; }