// ---------------------------------------------------------------------------------- // // 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 // 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(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; nCountResetIndex(); 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) 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; nTempHolderIndexmszFileList, 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