windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wsdu/wsdueng/wsdueng.cpp
2020-09-26 16:20:57 +08:00

655 lines
17 KiB
C++

#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;
}