windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wsdu/wsdueng/dudriver.cpp

1013 lines
32 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// ----------------------------------------------------------------------------------
//
// Created By RogerJ, October 3rd, 2000
// This CPP file has all the functions that related to driver detection (on W2K) and
// driver downloading. The setup item download part is in Wsdueng.cpp
//
// ----------------------------------------------------------------------------------
#include "Wsdueng.h"
#include <winspool.h>
// DuDriver.h includes definition of structures used in driver bitmap and bucket file, it is a
// cut and paste version of "bucket.h" (minus some unused function declaration)
#include "DuDriver.h"
#include "..\wsdu\Dynamic.h"
extern CDynamicUpdate* g_pDynamicUpdate;
// --------------------------------------------------------------------------------------------
// DLL Exposed function starts here
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
// Function Name: DuQueryUnsupportedDriversA()
// Function Description: This function is the entry point function of Win9x. It will construct
// the list of PnPId for searching of the web site and call DuDoSetUpItemDetection to get
// other item information
// Return Code: BOOL
// TRUE --- if succeed
// FALSE --- if failed, call GetLastError() to get the extensive error information
//
BOOL DuQueryUnsupportedDriversA (IN HANDLE hConnection, // connection handle
IN PCSTR *ListOfDriversNotOnCD, // multi-sz string array
OUT PDWORD pdwEstimatedTime,
OUT PDWORD pdwEstimatedSize)
{
LOG_block("CDynamicUpdate::DuQueryUnsupportedDriversA");
// parameter validation
if (INVALID_HANDLE_VALUE == hConnection ||
NULL == pdwEstimatedTime ||
NULL == pdwEstimatedSize )
{
LOG_error("Invalid Parameter");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// do setup item detection first
if (NULL == g_pDynamicUpdate)
return FALSE;
DWORD dwRetSetup, dwRetDriver;
dwRetSetup = dwRetDriver = 0;
g_pDynamicUpdate->ClearDownloadItemList();
dwRetSetup = g_pDynamicUpdate->DoSetupUpdateDetection();
if (ERROR_SUCCESS != dwRetSetup)
{
LOG_error("Setup item detection failed --- %d", dwRetSetup);
}
// do driver detection next
// clean up the hardware id list first
g_pDynamicUpdate->m_arrayHardwareId.RemoveAll();
// determine if there are drivers need download
if (ListOfDriversNotOnCD)
{
// iternate the PnPId list and construct the m_arrayHardwareId
PSTR* ListIternator = const_cast<PSTR*>(ListOfDriversNotOnCD);
while (*ListIternator)
{
g_pDynamicUpdate->m_arrayHardwareId.Add(*ListIternator);
ListIternator++;
}
if (!g_pDynamicUpdate->DoWindowsUpdateDriverDetection())
{
dwRetDriver = GetLastError();
LOG_error("Driver detection failed");
}
}
if (dwRetSetup && dwRetDriver)
{
LOG_error("Both Setup item and Driver detection failed");
return FALSE;
}
// determine the download time and download size
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
{
// At this point there was no error, but we have no items to download,
SetLastError(ERROR_NO_MORE_ITEMS);
return TRUE;
}
}
// ----------------------------------------------------------------------------------
// member function of CDynamicUpdate starts from here
// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
// Function Name: DoDriverDetection
// Function Description: This function will detect all the device currently installed
// in the machine and return (via member parameter) a multi-sz string array
// of all the hardware ids and the compatible ids. The array will be NULL
// terminated
// Return Value: BOOL
// TRUE for success
// FALSE for failure, use GetLastError() to retrieve error code
//
BOOL CDynamicUpdate::DoDriverDetection (void) // connection handle
{
// log
LOG_block("DuDoDriverDetection");
// Clean up and previous error code might exist
SetLastError(0);
BOOL fIsPrinterInfo6Supported = FALSE;
// this function will call some setup API which is only supported on a certain
// platform. We will do a platform detection here. If the current platform
// does not support all the setup API we need, bail out.
{
OSVERSIONINFO OsInfo;
ZeroMemory( (PVOID) &OsInfo, sizeof (OsInfo) );
OsInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (!GetVersionEx( &OsInfo ))
// Function call failed, last error is set by GetVersionEx()
return FALSE;
if ( VER_PLATFORM_WIN32_NT == OsInfo.dwPlatformId )
{
// WinNT, DU driver is supported only from W2K and up
if ( 4 >= OsInfo.dwMajorVersion )
{
// NT 3.51 or NT 4.0
LOG_error("DU driver is not supported on NT 3.51 or NT 4.0");
SetLastError(ERROR_OLD_WIN_VERSION);
return TRUE; // no detection to do, succeed
}
else
// Win2K and beyond
fIsPrinterInfo6Supported = TRUE;
}
else if ( VER_PLATFORM_WIN32_WINDOWS == OsInfo.dwPlatformId )
{
// Win9x, DU driver detection is supported only from Win98 and up
// for Win9x, we should call DuQueryUnsupportedDrivers() instead
// Since this function should also work for Win98 and up, we will
// allow this call
// ROGERJ, october 31th, 2000, remove driver support for win9x platform
//if ( 0 == OsInfo.dwMinorVersion )
//{
// // Win95
// LOG_error("DU driver is not supported on Win95");
// SetLastError(ERROR_OLD_WIN_VERSION);
// return FALSE;
//}
//if (90 <= OsInfo.dwMinorVersion)
// // WinME
// fIsPrinterInfo6Supported = TRUE;
LOG_error("DU driver is not supported on Win9x");
SetLastError(ERROR_OLD_WIN_VERSION);
return TRUE; // no detection to do, succeed
}
else
{
// Win 3.x and below, not supported
LOG_error("DU driver is not supported on Win 3.x");
SetLastError(ERROR_OLD_WIN_VERSION);
return FALSE;
}
}
// Do the driver detection
BOOL fRetValue = TRUE;
// clean up the hardware id list first
m_arrayHardwareId.RemoveAll();
// Get all the device class installed in the machine
HDEVINFO hDeviceInfoSet = INVALID_HANDLE_VALUE;
int nIndex = 0;
SP_DEVINFO_DATA DeviceInfoData;
if ( INVALID_HANDLE_VALUE ==
(hDeviceInfoSet = SetupDiGetClassDevs ( NULL, // class guid
NULL, // enumerator
NULL, // parent window handler
DIGCF_PRESENT|DIGCF_ALLCLASSES))) // all class, device presented
{
// function call failed, error will be set by Setup API
LOG_error("SetupDiGetClassDevs failed --- %d", GetLastError());
return FALSE;
}
// initialize SP_DEVINFO_DATA structure
ZeroMemory((PVOID)&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
while ( SetupDiEnumDeviceInfo( hDeviceInfoSet, // handle of device info set
nIndex++, // 0 based index
&DeviceInfoData)) // retrieved device info data
{
ULONG uHwidSize, uCompatidSize;
uHwidSize = uCompatidSize = 0;
unsigned char *pszBuffer = NULL;
DWORD dwError = 0;
// get the size needed for hard ware id
if (!SetupDiGetDeviceRegistryProperty( hDeviceInfoSet, // handle of device info set
&DeviceInfoData, // device info data
SPDRP_HARDWAREID, // hardware id
NULL, // reg data type
NULL, // buffer
0, // buffer size
&uHwidSize)) // out buffer size
{
if (!uHwidSize)
{
// missing a HWID is not catastrophic, we just need to skip this device node
continue;
}
dwError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != dwError)
{
LOG_error("SetupDiGetDeviceRegistryProperty 1st call --- %d, skipping device", dwError);
continue;
}
}
if (!SetupDiGetDeviceRegistryProperty( hDeviceInfoSet, // handle of device info set
&DeviceInfoData, // device info data
SPDRP_COMPATIBLEIDS , // compatible ids
NULL, // reg data type
NULL, // buffer
0, // buffer size
&uCompatidSize) && uCompatidSize) // out buffer size
{
dwError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != dwError)
{
LOG_error("SetupDiGetDeviceRegistryProperty 2nd call --- %d, skipping device", dwError);
continue;
}
}
// allocate memory for the multi-sz buffer
pszBuffer = new unsigned char [uHwidSize + uCompatidSize + 2];
if (!pszBuffer)
{
// out of memory
LOG_error("Out of memory");
fRetValue = FALSE;
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto ErrorReturn;
}
// initiliaze the buffer
ZeroMemory(pszBuffer, sizeof(char)*(uHwidSize + uCompatidSize + 2));
// get the hardware id and compatible id
if (uHwidSize && !SetupDiGetDeviceRegistryProperty( hDeviceInfoSet, // handle of device info set
&DeviceInfoData, // device info data
SPDRP_HARDWAREID, // hardware id
NULL, // reg data type
pszBuffer, // buffer
uHwidSize, // buffer size
NULL)) // out buffer size
{
dwError = GetLastError();
LOG_error("SetupDiGetDeviceRegistryProperty 3rd call --- %d, skipping device", dwError);
if (pszBuffer) delete [] pszBuffer;
pszBuffer = NULL;
continue;
}
if (uCompatidSize)
{
if (!SetupDiGetDeviceRegistryProperty( hDeviceInfoSet, // handle of device info set
&DeviceInfoData, // device info data
SPDRP_COMPATIBLEIDS , // compatible ids
NULL, // reg data type
pszBuffer + uHwidSize -1 , // buffer
uCompatidSize, // buffer size
NULL)) // out buffer size
{
dwError = GetLastError();
LOG_error("SetupDiGetDeviceRegistryProperty 4th call --- %d, skipping device", dwError);
if (pszBuffer) delete [] pszBuffer;
pszBuffer = NULL;
continue;
}
}
// output first hardware id to log file
LOG_out("HardwareID detected --- \"%s\"", pszBuffer);
// Test if the hardwareid we got is on the setup CD or not
if (!IsHardwareIdHasDriversOnCD((char*)pszBuffer))
{
// not on CD
// Add this multi-sz list to our hardware id list
LOG_out("HardwareID added --- \"%s\"", pszBuffer);
m_arrayHardwareId.Add((char*)pszBuffer);
}
else
LOG_out("HardwareID ignored --- \"%s\"", pszBuffer);
// re-initialize SP_DEVINFO_DATA structure
ZeroMemory((PVOID)&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
if (pszBuffer) delete [] pszBuffer;
pszBuffer = NULL;
} // end of while
if (ERROR_NO_MORE_ITEMS != GetLastError())
{
// Failed other than reach the end of the list
LOG_error("SetupDiEnumDeviceInfo failed --- %d", GetLastError());
fRetValue = FALSE;
}
ErrorReturn:
if ( INVALID_HANDLE_VALUE != hDeviceInfoSet)
SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
if (fIsPrinterInfo6Supported)
DoPrinterDriverDetection();
return fRetValue;
}
// --------------------------------------------------------------------------------------------
// Function Name: IsHardwareIdHasDriversOnCD()
// Function Description: This function take a multi-sz list and determins if any of the hardware
// id in the list is on setup CD.
// Return Code: BOOL
// TRUE --- if any one hardware id is on CD
// FALSE --- if all hardware id is not on CD
//
BOOL CDynamicUpdate::IsHardwareIdHasDriversOnCD(LPCSTR pszHardwareIdList)
{
LOG_block("FilterDriverListFromCD");
// parameter validation
if (NULL == pszHardwareIdList)
{
LOG_error("NULL parameter");
// since the pszHardwareIdList is NULL, which means all the hardwareid (zero) contained in the
// string is on CD, we will return TRUE here
return TRUE;
}
// call the callback function provided by setup to find out if there is a driver for this
// hardware id on CD
PNPID_INFO PnPInfo;
// initialize default state --- device supported, but driver not found
PnPInfo.fHandled = FALSE;
PnPInfo.fUnSupported = FALSE;
DWORD dwSizePnPInfo = (DWORD) sizeof(PNPID_INFO);
if (!(*m_pfnWinNT32Query) ( SETUPQUERYID_PNPID, // query flag
(PVOID)pszHardwareIdList, // multi-SZ list of HardwareId
0, // sizeof pszHardwarIdList, not used
(PVOID)&PnPInfo,
&dwSizePnPInfo))
{
LOG_error("Callback Function Failed --- %d", GetLastError());
return TRUE; // assume found
}
if (PnPInfo.fUnSupported)
LOG_out("HardwareID unsupported --- \"%s\"", pszHardwareIdList);
if (PnPInfo.fUnSupported || PnPInfo.fHandled)
return TRUE; // device is not supported or driver is found in CD
else
return FALSE; // device is supported and driver is not on CD
}
// ------------------------------------------------------------------------------------------------
// Function Name: DoWindowsUpdateDriverDetection
// Function Description: This function will take the member variable (multi-sz list) for hardware id
// not found in the CD and search for the driver on the site. If found, the function will add
// the file needed to be downloaded into the download list
// Return Code: BOOL
// TRUE --- if successful
// FALSE --- if failed, call GetLastError() to get extensive error information
//
BOOL CDynamicUpdate::DoWindowsUpdateDriverDetection()
{
LOG_block("CDynamicUpdate::DoWindowsUpdateDriverDetection");
BOOL fRetVal = TRUE;
if (!m_pV3->ReadGuidrvINF()) return FALSE;
// no driver presents on the catalog
if (!m_pV3->m_fHasDriver)
{
// need to ping back the drivers
m_arrayHardwareId.ResetIndex();
CMultiSZString* pSZTemp = NULL;
while ( NULL != (pSZTemp = m_arrayHardwareId.GetNextMultiSZString()))
{
if (pSZTemp->IsFound()) continue; // driver found for this device
pSZTemp->ResetIndex();
PingBack(DU_PINGBACK_DRIVERNOTFOUND, 0, pSZTemp->GetNextString(), FALSE);
}
return TRUE;
}
int nNumOfDevNeedDriver = m_arrayHardwareId.GetCount();
int nNumOfTotalPnPIds = m_arrayHardwareId.GetTotalStringCount();
// no driver is needed
if (!nNumOfDevNeedDriver || !nNumOfTotalPnPIds) return TRUE;
// download the bitmap file to memory
PCDM_HASHTABLE pBitMap = NULL;
DWORD dwLength = 0;
DWORD dwError = 0;
UINT *pnHashList = NULL;
int nIdCount = 0;
int nCount = 0;
CMultiSZString* pTemp = NULL;
PDRIVER_DOWNLOAD_INFO* pPlaceHolder = NULL;
int nPlaceHolderIndex = 0;
int nTempHolderIndex = 0;
char szBmpRelativeName[MAX_PATH];
ZeroMemory(szBmpRelativeName, MAX_PATH*sizeof(char));
wsprintfA(szBmpRelativeName, "%d/inventory.cdm", m_pV3->m_puidConsumerCatalog);
// get the bitmap file name on server
char szServerBitMapFileName [INTERNET_MAX_URL_LENGTH];
ZeroMemory(szServerBitMapFileName, INTERNET_MAX_URL_LENGTH*sizeof(char));
DuUrlCombine(szServerBitMapFileName, m_pV3->m_szV31ContentUrl, szBmpRelativeName);
// down load bitmap file to pBitMap
dwError = DownloadFileToMem( szServerBitMapFileName, // server file name
(PBYTE*) &pBitMap, // buffer, OUT
& dwLength, // buffer length, OUT
TRUE, // try to decompress
"inventory.cdm",
NULL);
if (ERROR_SUCCESS != dwError)
{
// download failed
LOG_error("Download bitmask.cdm failed --- %d", dwError);
fRetVal = FALSE;
goto CleanUp;
}
// allocate memory for hash list
pnHashList = new UINT [nNumOfTotalPnPIds];
if (!pnHashList)
{
LOG_error("Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
fRetVal = FALSE;
goto CleanUp;
}
ZeroMemory(pnHashList, nNumOfTotalPnPIds*sizeof(UINT));
// allocate memory for place holder list
pPlaceHolder = (PDRIVER_DOWNLOAD_INFO*) GlobalAlloc(GMEM_ZEROINIT, nNumOfDevNeedDriver * sizeof (PDRIVER_DOWNLOAD_INFO));
if (!pPlaceHolder)
{
LOG_error("Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
fRetVal = FALSE;
goto CleanUp;
}
m_arrayHardwareId.ResetIndex();
// go through every device that has no driver on the CD
for (nCount = 0; nCount<nNumOfDevNeedDriver; nCount++)
{
pTemp = m_arrayHardwareId.GetNextMultiSZString();
// error!
if (!pTemp) break;
// get each string from the multi-sz string
pTemp->ResetIndex();
LPCTSTR pTempId = pTemp->GetNextString();
while (*pTempId)
{
// Log
LOG_out("Searching driver for HardwareID --- %s", pTempId);
// get the hashed id list
UINT uHashValue = CDM_HwID2Hash(pTempId, pBitMap->hdr.iTableSize);
if (!uHashValue)
{
// uHashValue is 0, could be an error condition, need to call GetLastError() to determine
dwError = GetLastError();
if (ERROR_SUCCESS != dwError)
{
// Error happened
LOG_error("Invalid Hash Value --- %d", dwError);
// try next hardware id
pTempId = pTemp->GetNextString();
continue;
}
}
// find out if a hash value exists in the bitmap
if (0 != ((pBitMap->pData)[(uHashValue/8)] & (0x80 >> (uHashValue%8))))
{
// Log
LOG_out ("Bucket file %d", uHashValue);
// match found, add to pnHashList
// check see if the same hash already in the list, if not, add it to the list
int k;
for (k = 0; k<nIdCount; k++)
if (uHashValue == pnHashList[k]) break;
if (k >= nIdCount)
pnHashList[nIdCount++] = uHashValue;
}
pTempId = pTemp->GetNextString();
}
}
// now we got all the bucket file number we need to download
for (nCount = 0; nCount < nIdCount; nCount++)
{
// read bucket file
char szBucketFileName[MAX_PATH];
ZeroMemory(szBucketFileName, MAX_PATH*sizeof(char));
char szServerBKFFullName [INTERNET_MAX_URL_LENGTH];
ZeroMemory(szServerBKFFullName, INTERNET_MAX_URL_LENGTH*sizeof(char));
// get bucket file name without the URL
wsprintfA(szBucketFileName, "%d/%d.bkf", m_pV3->m_puidConsumerCatalog, pnHashList[nCount]);
// get bucket file name with URL
DuUrlCombine(szServerBKFFullName, m_pV3->m_szV31ContentUrl, szBucketFileName);
// reset szBucketFileName to local bucket file name
wsprintfA(szBucketFileName,"%d.bkf", pnHashList[nCount]);
// download bucket file to memory
LOG_out("Download bucket file %s", szBucketFileName);
PBYTE pBKFFile = NULL;
dwError = DownloadFileToMem(szServerBKFFullName, // server file name
&pBKFFile, // buffer
&dwLength, // buffer length
TRUE, // try to decompress
szBucketFileName,
NULL);
if (ERROR_SUCCESS != dwError)
{
LOG_error("Failed to download %s --- %d", szBucketFileName, dwError);
if (pBKFFile) GlobalFree(pBKFFile);
fRetVal = FALSE;
goto CleanUp;
}
// download each bucket file and parse the bucket file to get the correct cabinet file
UINT uBKFIndex = 0;
while ( uBKFIndex < dwLength )
{
PCDM_RECORD_HEADER pCdmHeader = (PCDM_RECORD_HEADER) (pBKFFile + uBKFIndex);
if (!m_pV3->IsPUIDExcluded(pCdmHeader->puid))
{
LPCSTR pTempHardwareid = (LPCSTR) ((PBYTE)pCdmHeader + sizeof(CDM_RECORD_HEADER));
LPCSTR pRememberedHWID = pTempHardwareid;
// parse the bucket file to find a PnPId match
// only get the hardware id, we don't care about any other information for DU, thus, we
// don't need to parse them
PosIndex PI;
if (m_arrayHardwareId.PositionIndex (pTempHardwareid, &PI))
{
LOG_out("HardwareID '%s' found in bucket file '%s'", pTempHardwareid, szBucketFileName);
// prune by locale
if (!GETBIT(m_pV3->m_pBitMaskCDM, pCdmHeader->nBitmaskIdx))
{
// masked out
LOG_out("HardwareID %s is masked out.", pTempHardwareid);
}
else
{
// match found
// first get necessary infomation
// get DriverVer
for (int t=0; t<4; t++)
{
pTempHardwareid += (lstrlenA(pTempHardwareid) + 1);
}
// now pTempHardwareid points to szDriverVer
// DriverVer is of format mm/dd/yyyy, change it into a number
// we set every month to 31 day, every year to 31 *12 days are construct
// a number start for 01/01/1998
int nTempYear = (pTempHardwareid[6]-'0')*1000 +(pTempHardwareid[7]-'0')*100 +
(pTempHardwareid[8]-'0')*10 +(pTempHardwareid[9]-'0');
int nTempMonth = (pTempHardwareid[0]-'0')*10+pTempHardwareid[1]-'0';
int nTempDay = (pTempHardwareid[3]-'0')*10+pTempHardwareid[4]-'0';
// no driver in windows update database has a date earlier than 1999.
// set to 1998 as the earliest date.
// NOTE: this will still work for drivers before 1998
int nTempDriverVer = (nTempYear - 1998)*31*12 + (nTempMonth-1)*31 +(nTempDay-1);
// get the cabinet file name
// now pTempHardwareid points to pszCabFileTitle
pTempHardwareid += (lstrlenA(pTempHardwareid) + 1);
char szAltName[MAX_PATH];
ZeroMemory(szAltName, MAX_PATH*sizeof(char));
// third see if the driver is excluded by guidrvs.inf
if (m_pV3->GetAltName(pTempHardwareid, szAltName, MAX_PATH)
&& !m_pV3->IsDriverExcluded(szAltName, pRememberedHWID))
{
// third, determine if a better match is already in the place holder
BOOL fFound = FALSE;
for (nTempHolderIndex = 0; nTempHolderIndex < nPlaceHolderIndex; nTempHolderIndex++)
{
if ((pPlaceHolder[nTempHolderIndex]->Position.x == PI.x))
{
// Driver for same device is found
fFound = TRUE;
if (pPlaceHolder[nTempHolderIndex]->Position.y < PI.y)
{
// a better matched driver is already in the place holder list
// do nothing
LOG_out("A better matched is already found");
}
else if (pPlaceHolder[nTempHolderIndex]->Position.y > PI.y)
{
// a worse matched driver is already in the place holder list
// replace it
pPlaceHolder[nTempHolderIndex]->Position.x = PI.x;
pPlaceHolder[nTempHolderIndex]->Position.y = PI.y;
pPlaceHolder[nTempHolderIndex]->nDriverVer = nTempDriverVer;
pPlaceHolder[nTempHolderIndex]->puid = pCdmHeader->puid;
lstrcpy(pPlaceHolder[nTempHolderIndex]->szCabFile, pTempHardwareid);
LOG_out("Replaced an old match");
}
else
{
LOG_out("Same match found, need to compare DriverVer");
// need to compare DriverVer for the same match
if (nTempDriverVer > pPlaceHolder[nTempHolderIndex]->nDriverVer)
{
// older driver in the list
// replace it
pPlaceHolder[nTempHolderIndex]->Position.x = PI.x;
pPlaceHolder[nTempHolderIndex]->Position.y = PI.y;
pPlaceHolder[nTempHolderIndex]->nDriverVer = nTempDriverVer;
pPlaceHolder[nTempHolderIndex]->puid = pCdmHeader->puid;
lstrcpy(pPlaceHolder[nTempHolderIndex]->szCabFile, pTempHardwareid);
LOG_out("Replaced an old match");
}
else
LOG_out("A better matched is already found");
}
break;
}
}
if (!fFound)
{
m_arrayHardwareId.CheckFound(PI.x); // mark as found
// not found, new entry
PDRIVER_DOWNLOAD_INFO pNewHolder = new DRIVER_DOWNLOAD_INFO;
if (!pNewHolder)
{
LOG_error("Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
fRetVal = FALSE;
goto CleanUp;
}
pNewHolder->Position.x = PI.x;
pNewHolder->Position.y = PI.y;
pNewHolder->nDriverVer = nTempDriverVer;
pNewHolder->puid = pCdmHeader->puid;
lstrcpy(pNewHolder->szCabFile, pTempHardwareid);
// add to list
pPlaceHolder[nPlaceHolderIndex++] = pNewHolder;
LOG_out("New match found, add to download list");
}
}
}
}
}
uBKFIndex += pCdmHeader->cnRecordLength; // move to next record
}
// free bucket file memory
SafeGlobalFree(pBKFFile);
pBKFFile = NULL;
}
// now we have a list of driver in pPlaceHolder that are best for this machine
// add all to download list
for (nTempHolderIndex=0; nTempHolderIndex<nPlaceHolderIndex; nTempHolderIndex++)
{
// fill in the download item structure
DOWNLOADITEM* pDownloadDriver = (DOWNLOADITEM*) GlobalAlloc(GMEM_ZEROINIT, sizeof(DOWNLOADITEM));
if (!pDownloadDriver)
{
LOG_error("Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
fRetVal = FALSE;
goto CleanUp;
}
lstrcpyA(pDownloadDriver->mszFileList, pPlaceHolder[nTempHolderIndex]->szCabFile);
pDownloadDriver->iNumberOfCabs = 1; // always 1 cab 1 driver
pDownloadDriver->puid = pPlaceHolder[nTempHolderIndex]->puid;
char pszDownloadUrl [INTERNET_MAX_URL_LENGTH];
ZeroMemory(pszDownloadUrl, INTERNET_MAX_URL_LENGTH*sizeof(char));
DuUrlCombine(pszDownloadUrl, m_pV3->m_szCabPoolUrl, pPlaceHolder[nTempHolderIndex]->szCabFile);
dwError = OpenHttpConnection(pszDownloadUrl, FALSE);
if (ERROR_SUCCESS != dwError)
{
// Log error
LOG_error("Failed to open internet connection --- %d", dwError);
pDownloadDriver->dwTotalFileSize = 102400; // default to 100k
continue;
}
// get file size from HTTP header
DWORD dwQueryLength = sizeof(DWORD);
if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
(LPVOID)&pDownloadDriver->dwTotalFileSize , &dwQueryLength, NULL) )
{
dwError = GetLastError();
LOG_error("HttpQueryInfo Failed on File %s, Error %d", pszDownloadUrl, dwError);
pDownloadDriver->dwTotalFileSize = 102400; // default to 100k
}
SafeInternetCloseHandle(m_hOpenRequest);
// Add the new item into download item list
EnterDownloadListCriticalSection();
AddDownloadItemToList(pDownloadDriver);
LeaveDownloadListCriticalSection();
}
// we need to ping the pnpid back for all the devices what does not has a driver found
m_arrayHardwareId.ResetIndex();
CMultiSZString* pSZTemp = NULL;
while ( NULL != (pSZTemp = m_arrayHardwareId.GetNextMultiSZString()))
{
if (pSZTemp->IsFound()) continue; // driver found for this device
pSZTemp->ResetIndex();
PingBack(DU_PINGBACK_DRIVERNOTFOUND, 0, pSZTemp->GetNextString(), FALSE);
}
CleanUp:
PlaceHolderCleanUp(pPlaceHolder, nNumOfDevNeedDriver);
SafeGlobalFree(pPlaceHolder);
SafeGlobalFree(pBitMap);
if (pnHashList) delete [] pnHashList;
return fRetVal;
}
// Utility function starts here
//These functions form a hash lookup for hwIDs.
static ULONG HashFunction(
IN ULONG seed //Seed value to use for hashing hwid.
) {
ULONG q;
ULONG r;
ULONG a;
ULONG m;
ULONG val;
q = 127773L;
r = 2836L;
a = 16807L;
m = 2147483647;
val = ((seed % q) * a) - (seed / q) * r;
if(((long)val) <= 0)
val = val + m;
return val;
}
//These functions form a hash lookup for hwIDs.
ULONG CDM_HwID2Hash(
IN LPCSTR szHwID, //Hardware id being hashed.
IN ULONG iTableSize //Size of downloaded hash table.
) {
SetLastError(0);
if (0 == iTableSize)
{
SetLastError(ERROR_INVALID_DATA);
return 0; // error
}
ULONG ulHashIndex = 1;
while(*szHwID)
{
if (*szHwID > 127 || *szHwID < 0)
{
// an extended ANSCII value, not valid
SetLastError(ERROR_INVALID_DATA);
return 0;
}
ulHashIndex = ulHashIndex + HashFunction(ulHashIndex + (ULONG)(INT_PTR)CharUpper((LPSTR)*szHwID));
szHwID++;
}
return (ulHashIndex % iTableSize);
}
// ------------------------------------------------------------------------------------
// Function Name: DoPrinterDriverDetection
// Function Description: This function will detect all locally installed printer and add
// the printer Hwid into out device list
// Return Value: BOOL
// TRUE for succeed
// FALSE for failure
BOOL CDynamicUpdate::DoPrinterDriverDetection()
{
LOG_block("CDynamicUpdate::DoPrinterDriverDetection()");
// Get Printers' Hwid
// Note: This method only worked on Win2K / WinME. If we are at other 9x, printer will not be supported
// by this function
DWORD nBytesNeeded;
DWORD nDriverRetrieved;
DWORD dwError;
nBytesNeeded = nDriverRetrieved = dwError = 0;
BYTE *pBuffer = NULL;
BOOL fRetValue = FALSE;
DRIVER_INFO_6 * pPrinterInfo = NULL;
if (!EnumPrinterDriversA(NULL, // only enum local drivers
NULL, // use default enviroment
6, // use DRIVER_INFO_6
NULL, // no out information
0, // out buffer is zero
&nBytesNeeded,
&nDriverRetrieved ))
{
if (ERROR_INSUFFICIENT_BUFFER != (dwError = GetLastError()))
{
// Failed
LOG_error("EnumPrinterDrivers 1st call failed --- %d",dwError);
goto ErrorReturn;
}
}
if (!nBytesNeeded)
LOG_out("No local printers for this machine");
else
{
pBuffer = new BYTE [nBytesNeeded];
int nCount = 0;
if (!pBuffer)
{
LOG_error("Insufficient memory when locating printer string");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto ErrorReturn;
}
// get printer driver information;
if (!EnumPrinterDriversA( NULL, // only enum local drivers
NULL, // use default enviroment
6, // use DRIVER_INFO_6
pBuffer, // no out information
nBytesNeeded, // out buffer is zero
&nBytesNeeded,
&nDriverRetrieved ))
{
if (ERROR_INSUFFICIENT_BUFFER != (dwError = GetLastError()))
{
// Failed
LOG_error("EnumPrinterDrivers 1st call failed --- %d",dwError);
goto ErrorReturn;
}
}
// get individual hwid
for (nCount=0; nCount<(int)nDriverRetrieved; nCount++)
{
pPrinterInfo = &((DRIVER_INFO_6*)pBuffer)[nCount];
// record printer driver information
// output printer hardware id to log file
LOG_out("HardwareID detected --- \"%s\"", pPrinterInfo->pszHardwareID);
// Test if the hardwareid we got is on the setup CD or not
if (!IsHardwareIdHasDriversOnCD((char*)pPrinterInfo->pszHardwareID))
{
// not on CD
// Add this multi-sz list to our hardware id list
LOG_out("HardwareID added --- \"%s\"", pPrinterInfo->pszHardwareID);
// for Windows Update, we need fake the printer id as
// orignial_id&manufacteur&name&provider to distinguish between monolithic and unidriver
int nSizeOfFakeId = lstrlenA(pPrinterInfo->pszHardwareID) +
lstrlenA(pPrinterInfo->pszMfgName) +
lstrlenA(pPrinterInfo->pName) +
lstrlenA(pPrinterInfo->pszProvider) + 3 + 2; // 3 for 3 & sign, 2 for double NULL termination
char* szFakeId = new char [nSizeOfFakeId];
if (!szFakeId)
{
LOG_error("Out of memory");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto ErrorReturn;
}
ZeroMemory(szFakeId, nSizeOfFakeId * sizeof(char));
lstrcpyA(szFakeId,pPrinterInfo->pszHardwareID);
lstrcatA(szFakeId,"&");
lstrcatA(szFakeId,pPrinterInfo->pszMfgName);
lstrcatA(szFakeId,"&");
lstrcatA(szFakeId,pPrinterInfo->pName);
lstrcatA(szFakeId,"&");
lstrcatA(szFakeId,pPrinterInfo->pszProvider);
// Add to hardware id list
m_arrayHardwareId.Add(szFakeId);
delete [] szFakeId;
}
}
}
fRetValue = TRUE;
ErrorReturn:
if (pBuffer) delete [] pBuffer;
return fRetValue;
}
void PlaceHolderCleanUp(PDRIVER_DOWNLOAD_INFO* pTemp, int nTotal)
{
if (NULL == pTemp)
return;
for (int i=0; i<nTotal; i++)
{
if (pTemp[i])
{
PDRIVER_DOWNLOAD_INFO pDelete = pTemp[i];
delete pDelete;
}
else
break;
}
}