|
|
//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: cdmi.cpp
//
// Description:
//
// Functions exported by IUEngine.dll for use by CDM.DLL
//
// InternalDetFilesDownloaded
// InternalDownloadGetUpdatedFiles
// InternalDownloadUpdatedFiles
// InternalFindMatchingDriver
// InternalLogDriverNotFound
// InternalQueryDetectionFiles
//
//=======================================================================
#include "iuengine.h"
#include "cdmp.h"
#include <setupapi.h>
#include <cfgmgr32.h>
#include <shlwapi.h>
#include <shellapi.h>
#include <wininet.h>
#include <osdet.h>
#include <fileutil.h>
#include "iuxml.h"
#include <wuiutest.h>
const CHAR SZ_APW_LIST[] = "Downloading printer list for Add Printer Wizard"; const CHAR SZ_FIND_MATCH[] = "Finding matching driver"; const CHAR SZ_OPENING_HS[] = "Opening Help and Support with: ";
void WINAPI InternalDetFilesDownloaded( IN HANDLE hConnection ) { LOG_Block("InternalDetFilesDownloaded"); //
// NOTE: This function is only used by WinME to expand the
// V3 buckets.cab (see commented out code below) and has no use
// in V4 (IU) but remains for backwards compatibility of the export API.
//
LOG_ErrorMsg(E_NOTIMPL); }
// Win 98 entry point
// This function allows Windows 98 to call the same entry points as NT.
// The function returns TRUE if the download succeeds and FALSE if it
// does not.
//
// Win 98 DOWNLOADINFO
// typedef struct _DOWNLOADINFOWIN98
// {
// DWORD dwDownloadInfoSize; // size of this structure - validate param (not validated in V3)
// LPTSTR lpHardwareIDs; // multi_sz list of Hardware PnP IDs - only use first string
// LPTSTR lpCompatIDs; // multi_sz list of compatible IDs - never used
// LPTSTR lpFile; // File name (string) - never used
// OSVERSIONINFO OSVersionInfo; //OSVERSIONINFO from GetVersionEx() - never used
// DWORD dwFlags; //Flags - never used
// DWORD dwClientID; //Client ID - never used
// } DOWNLOADINFOWIN98, *PDOWNLOADINFOWIN98;
//
// typedef struct _DOWNLOADINFO {
// DWORD dwDownloadInfoSize;
// LPCWSTR lpHardwareIDs; - copied from DOWNLOADINFOWIN98 using T2OLE()
// LPCWSTR lpDeviceInstanceID; - in V3, match was sometimes found and this was filled in
// - but for IU we just let InternalDownloadUpdatedFiles do it all
// LPCWSTR lpFile;
// OSVERSIONINFOW OSVersionInfo;
// DWORD dwArchitecture; - set to PROCESSOR_ARCHITECTURE_UNKNOWN per V3 code
// DWORD dwFlags;
// DWORD dwClientID;
// LCID localid; - not set in V3
// } DOWNLOADINFO, *PDOWNLOADINFO;
BOOL InternalDownloadGetUpdatedFiles( IN PDOWNLOADINFOWIN98 pDownloadInfoWin98, //The win98 download info structure is
//slightly different that the NT version
//so this function handles conversion.
IN OUT LPTSTR lpDownloadPath, //returned Download path to the downloaded
//cab files.
IN UINT uSize //size of passed in download path buffer.
) { USES_IU_CONVERSION;
LOG_Block("InternalDownloadGetUpdatedFiles");
if (NULL == pDownloadInfoWin98 || NULL == pDownloadInfoWin98->lpHardwareIDs || sizeof(DOWNLOADINFOWIN98) != pDownloadInfoWin98->dwDownloadInfoSize) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; }
HRESULT hr; BOOL fOK = FALSE; DOWNLOADINFO info; ZeroMemory(&info, sizeof(info)); info.dwDownloadInfoSize = sizeof(DOWNLOADINFO); info.dwArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN; //
// NOTE: In V3 sources, we only use the _first_ HWID in the Multi_SZ pDownloadInfoWin98->lpHardwareIDs
// and compare that against all enumerated hardware IDs.
// In IU, this compare will be done in InternalDownloadUpdatedFiles, so we just pass through
// the HWID
//
// Prefast - using too much stack, so move HWIDBuff to heap
LPWSTR pwszHWIDBuff = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, HWID_LEN); if (NULL != pwszHWIDBuff) { // buffer size obtained from HeapAlloc call above.
hr = StringCbCopyExW(pwszHWIDBuff, HWID_LEN, T2OLE(pDownloadInfoWin98->lpHardwareIDs), NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SafeHeapFree(pwszHWIDBuff); LOG_ErrorMsg(hr); return FALSE; } info.lpHardwareIDs = pwszHWIDBuff;
WCHAR wszbufPath[MAX_PATH]; UINT uRequiredSize; //
// We no longer have context handles, so just pass 1 to make InternalDownloadUpdatedFiles happy.
//
fOK = InternalDownloadUpdatedFiles((HANDLE) 1, NULL, &info, wszbufPath, uSize * (sizeof(WCHAR)/sizeof(TCHAR)), &uRequiredSize); } else { LOG_ErrorMsg(E_OUTOFMEMORY); }
if (fOK) { hr = StringCbCopyEx(lpDownloadPath, uSize, OLE2T(pwszHWIDBuff), NULL, NULL, MISTSAFE_STRING_FLAGS | STRSAFE_NO_TRUNCATION); if (FAILED(hr)) fOK = FALSE; } SafeHeapFree(pwszHWIDBuff);
return fOK; }
//This function downloads the specified CDM package. The hConnection handle must have
//been returned from the OpenCDMContext() API.
//
//This function Returns TRUE if download is successful GetLastError() will return
//the error code indicating the reason that the call failed.
BOOL WINAPI InternalDownloadUpdatedFiles( IN HANDLE hConnection, //Connection handle from OpenCDMContext() API.
IN HWND hwnd, //Window handle for call context
IN PDOWNLOADINFO pDownloadInfo, //download information structure describing
//package to be read from server
OUT LPWSTR lpDownloadPath, //local computer directory location of the
//downloaded files
IN UINT uSize, // Not Used (we require the buffer to be a WCHAR buffer
// MAX_PATH characters long)
OUT PUINT /*puRequiredSize*/ // Not used (we don't validate uSize - see comments inline)
) { USES_IU_CONVERSION;
LOG_Block("InternalDownloadUpdatedFiles");
TCHAR szDownloadPathTmp[MAX_PATH]; BSTR bstrXmlCatalog = NULL; HRESULT hr = S_OK; BOOL fPlist = FALSE;
if (NULL == g_pCDMEngUpdate) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
//
// Reset Quit Event in case client retries after a SetOperationMode
//
ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
// Since all current platforms call DownloadUpdatedFiles with MAX_PATH TCHARS, we will just
// require MAX_PATH for all callers.
//
// UNFORTUNATELY, NewDev passes up uSize in bytes and the Printer folks pass us characters,
// so there is no way to validate this parameter. In addition, we won't bother validating
// puRequiredSize since we never use it (would be return chars or bytes?)
if (NULL == pDownloadInfo || NULL == lpDownloadPath || NULL == hConnection) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
if (g_pCDMEngUpdate->m_fOfflineMode) { SetLastError(ERROR_REM_NOT_LIST); return FALSE; }
//
// Check to see if this is a printer catalog request. Note: 3FBF5B30-DEB4-11D1-AC97-00A0C903492B
// is not defined in any system or private headers and is copied from
// \\index2\ntsrc\printscan\print\spooler\splsetup\util.c (or equiv.)
//
// Only the first string passed in lpHardwareIDs is relevant to this test
fPlist = ( NULL != pDownloadInfo->lpHardwareIDs && CSTR_EQUAL == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, L"3FBF5B30-DEB4-11D1-AC97-00A0C903492B", -1, pDownloadInfo->lpHardwareIDs, -1) );
OSVERSIONINFO osVersionInfo; ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFO)); osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&osVersionInfo)) { Win32MsgSetHrGotoCleanup(GetLastError()); } //
// Only support printers for Win2K up & WinME
//
if ( fPlist && !( ( // Win2K (NT 5.0) up
(VER_PLATFORM_WIN32_NT == osVersionInfo.dwPlatformId) && (4 < osVersionInfo.dwMajorVersion) ) || ( // WinME (or higher)
(VER_PLATFORM_WIN32_WINDOWS == osVersionInfo.dwPlatformId) && (90 <= osVersionInfo.dwMinorVersion) ) ) ) { CleanUpIfFailedAndSetHrMsg(E_NOTIMPL); } hr = GetPackage(fPlist ? GET_PRINTER_INFS : DOWNLOAD_DRIVER, pDownloadInfo, szDownloadPathTmp, ARRAYSIZE(szDownloadPathTmp), &bstrXmlCatalog); if (FAILED(hr)) { lpDownloadPath[0] = 0; //
// Map an HRESULT to a WIN32 error value
// Note: This assumes that WIN32 errors fall in the range -32k to 32k,
// same as HRESULT_FROM_WIN32 that packaged them into HRESULT.
//
SetLastError(hr & 0x0000FFFF); goto CleanUp; } else { // The comment above says that different callers pass in different types
// of values for uSize, so the function assumes that the buffer is MAX_PATH.
// Attempting to find out if we can force callers into this function to
// do the right thing. For now, assume buffer is MAX_PATH.
hr = StringCchCopyExW(lpDownloadPath, MAX_PATH, T2OLE(szDownloadPathTmp), NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto CleanUp; } LOG_Driver(_T("Downloaded files for %s located at %S"), pDownloadInfo->lpHardwareIDs, lpDownloadPath); goto CleanUp; }
CleanUp:
SysFreeString(bstrXmlCatalog);
if (fPlist) { if (SUCCEEDED(hr)) { LogMessage(SZ_APW_LIST); } else { LogError(hr, SZ_APW_LIST); } } else { if (SUCCEEDED(hr)) { LogMessage("Downloaded driver for %ls at %ls", pDownloadInfo->lpHardwareIDs, lpDownloadPath); } else { LogError(hr, "Driver download failed for %ls", pDownloadInfo->lpHardwareIDs); } }
return SUCCEEDED(hr); }
BOOL WINAPI InternalFindMatchingDriver( IN HANDLE hConnection, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo ) { LOG_Block("InternalFindMatchingDriver");
BSTR bstrXmlCatalog = NULL; BSTR bstrHWID = NULL; BSTR bstrDisplayName = NULL; BSTR bstrDriverName = NULL; BSTR bstrMfgName = NULL; BSTR bstrDriverProvider = NULL; BSTR bstrDriverVer = NULL; BSTR bstrArchitecture = NULL;
HRESULT hr = S_OK; CXmlCatalog* pCatalog = NULL; HANDLE_NODE hCatalogItem; HANDLE_NODE hProvider; HANDLE_NODELIST hItemList; HANDLE_NODELIST hProviderList; BOOL fIsPrinter;
if (NULL == g_pCDMEngUpdate) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
//
// Reset Quit Event in case client retries after a SetOperationMode
//
ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
if (NULL == pDownloadInfo || NULL == pWuDriverInfo || NULL == hConnection) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
if (g_pCDMEngUpdate->m_fOfflineMode) { SetLastError(ERROR_REM_NOT_LIST); return FALSE; }
CleanUpFailedAllocSetHrMsg(pCatalog = (CXmlCatalog*) new CXmlCatalog);
//
// Get the catalog XML
//
CleanUpIfFailedAndSetHr(GetPackage(GET_CATALOG_XML, pDownloadInfo, NULL, 0, &bstrXmlCatalog)); //
// Load the XML and get the <item/> list and node of first item (only one in CDM case)
//
CleanUpIfFailedAndSetHr(pCatalog->LoadXMLDocument(bstrXmlCatalog, g_pCDMEngUpdate->m_fOfflineMode));
hProviderList = pCatalog->GetFirstProvider(&hProvider); if (HANDLE_NODELIST_INVALID == hProviderList || HANDLE_NODE_INVALID == hProvider) { hr = S_FALSE; goto CleanUp; } hItemList = pCatalog->GetFirstItem(hProvider, &hCatalogItem); if (HANDLE_NODELIST_INVALID == hItemList || HANDLE_NODE_INVALID == hProvider) { hr = S_FALSE; goto CleanUp; } //
// Populate pWuDriverInfo with data from the catalog
//
CleanUpIfFailedAndSetHr(pCatalog->GetDriverInfoEx(hCatalogItem, &fIsPrinter, &bstrHWID, &bstrDriverVer, &bstrDisplayName, &bstrDriverName, &bstrDriverProvider, &bstrMfgName, &bstrArchitecture)); hr = StringCchCopyExW(pWuDriverInfo->wszHardwareID, ARRAYSIZE(pWuDriverInfo->wszHardwareID), bstrHWID, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto CleanUp;
hr = StringCchCopyExW(pWuDriverInfo->wszDescription, ARRAYSIZE(pWuDriverInfo->wszDescription), bstrDisplayName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto CleanUp; //
// Convert from ISO to DriverVer date format
//
// DriverVer: "mm-dd-yyyy" <--> ISO 8601: "yyyy-mm-dd"
// index: 0123456789 0123456789
//
if (ARRAYSIZE(pWuDriverInfo->wszDriverVer) >= 11 && SysStringLen(bstrDriverVer) == 10) { pWuDriverInfo->wszDriverVer[0] = bstrDriverVer[5]; pWuDriverInfo->wszDriverVer[1] = bstrDriverVer[6]; pWuDriverInfo->wszDriverVer[2] = L'-'; pWuDriverInfo->wszDriverVer[3] = bstrDriverVer[8]; pWuDriverInfo->wszDriverVer[4] = bstrDriverVer[9]; pWuDriverInfo->wszDriverVer[5] = L'-'; pWuDriverInfo->wszDriverVer[6] = bstrDriverVer[0]; pWuDriverInfo->wszDriverVer[7] = bstrDriverVer[1]; pWuDriverInfo->wszDriverVer[8] = bstrDriverVer[2]; pWuDriverInfo->wszDriverVer[9] = bstrDriverVer[3]; pWuDriverInfo->wszDriverVer[10] = L'\0'; } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto CleanUp; }
if(fIsPrinter) { hr = StringCchCopyExW(pWuDriverInfo->wszMfgName, ARRAYSIZE(pWuDriverInfo->wszMfgName), bstrMfgName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto CleanUp;
hr = StringCchCopyExW(pWuDriverInfo->wszProviderName, ARRAYSIZE(pWuDriverInfo->wszProviderName), bstrDriverProvider, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto CleanUp; }
CleanUp:
if (S_OK == hr) { LogMessage("Found matching driver for %ls, %ls, %ls", bstrHWID, bstrDisplayName, bstrDriverVer); } else { if (S_FALSE == hr) { if (pDownloadInfo->lpDeviceInstanceID) { LogMessage("Didn't find matching driver for %ls", pDownloadInfo->lpDeviceInstanceID); } else if (pDownloadInfo->lpHardwareIDs) { LogMessage("Didn't find matching driver for %ls", pDownloadInfo->lpHardwareIDs); } else { LogMessage("Didn't find matching driver"); } } else // error happened
{ if (pDownloadInfo->lpDeviceInstanceID) { LogError(hr, "%s for %ls", SZ_FIND_MATCH, pDownloadInfo->lpDeviceInstanceID); } else if (pDownloadInfo->lpHardwareIDs) { LogError(hr, "%s for %ls", SZ_FIND_MATCH, pDownloadInfo->lpHardwareIDs); } else { LogError(hr, SZ_FIND_MATCH); } }
}
SysFreeString(bstrXmlCatalog); SysFreeString(bstrHWID); SysFreeString(bstrDisplayName); SysFreeString(bstrDriverName); SysFreeString(bstrMfgName); SysFreeString(bstrDriverProvider); SysFreeString(bstrDriverVer); SysFreeString(bstrArchitecture);
if (NULL != pCatalog) { delete pCatalog; }
return SUCCEEDED(hr); }
// supports offline logging
// hConnection NOT used at all
// no network connection or osdet.dll needed for languauge, SKU, platform detection
void WINAPI InternalLogDriverNotFound( IN HANDLE hConnection, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags // dwFlags could be either 0 or BEGINLOGFLAG from NEWDEV
) { USES_IU_CONVERSION;
LOG_Block("InternalLogDriverNotFound");
#if !(defined(_UNICODE) || defined(UNICODE))
LOG_ErrorMsg(E_NOTIMPL); return; #else
HRESULT hr = E_FAIL; DWORD dwBytes; TCHAR* pszBuff = NULL; ULONG ulLength; DWORD dwDeviceCount = 0; DWORD dwRank = 0;
TCHAR szUniqueFilename[MAX_PATH] = _T(""); DWORD dwWritten; DEVINST devinst; bool fXmlFileError = false; HANDLE hFile = NULL; BSTR bstrXmlSystemSpec = NULL; BSTR bstrThisID = NULL; HANDLE_NODE hDevices = HANDLE_NODE_INVALID;
static CDeviceInstanceIdArray apszDIID; //device instance id list
LPWSTR pDIID = NULL; //Device Instance ID
CXmlSystemSpec xmlSpec;
if (NULL == g_pCDMEngUpdate) { SetLastError(ERROR_OUTOFMEMORY); return; }
//
// Reset Quit Event in case client retries after a SetOperationMode
//
ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
//
// Only allow BEGINLOGFLAG or no flags
//
if (!(0 == dwFlags || BEGINLOGFLAG == dwFlags)) { LOG_ErrorMsg(E_INVALIDARG); return; } //
// If no flags, then lpDeviceInstanceID must be valid
//
if (0 == dwFlags && NULL == lpDeviceInstanceID) { LOG_ErrorMsg(E_INVALIDARG); return; }
LogMessage("Started process to regester driver not found with Help Center. Not completing this process may not be error.");
IU_PLATFORM_INFO iuPlatformInfo; //
// We need iuPlatformInfo for both <platform> and <devices> elements
// NOTE: iuPlatformInfo is initialized by DetectClientIUPlatform, and BSTRs must be
// freed in CleanUp (don't just there before this call).
//
CleanUpIfFailedAndSetHr(DetectClientIUPlatform(&iuPlatformInfo));
//
// Should only be called on Whistler up except CHK builds can run on Win2K
//
if ( !( (VER_PLATFORM_WIN32_NT == iuPlatformInfo.osVersionInfoEx.dwPlatformId) && (4 < iuPlatformInfo.osVersionInfoEx.dwMajorVersion) && (0 < iuPlatformInfo.osVersionInfoEx.dwMinorVersion) ) ) { LOG_Driver(_T("Should only be called on Whistler or greater")); CleanUpIfFailedAndSetHr(E_NOTIMPL); }
if (NULL != lpDeviceInstanceID) { LOG_Driver(_T("DeviceInstanceID is %s"), lpDeviceInstanceID); //
// Add the DeviceInstanceID to the list
//
if (-1 == apszDIID.Add(lpDeviceInstanceID)) { goto CleanUp; } }
if (0 == (dwFlags & BEGINLOGFLAG) || 0 == apszDIID.Size()) { // not last log request or nothing to log
LOG_Driver(_T("Won't log to hardware_XXX.xml until we get BEGINLOGFLAG when we have cached at least 1 HWID")); return; }
////////////////////////////////////////////
// ELSE, WRITE XML FILE and call HelpCenter
////////////////////////////////////////////
hr = OpenUniqueFileName(szUniqueFilename, ARRAYSIZE(szUniqueFilename), hFile); if (S_OK != hr) { fXmlFileError = true; goto CleanUp; }
//
// Write Unicode Header
//
if (0 == WriteFile(hFile, (LPCVOID) &UNICODEHDR, ARRAYSIZE(UNICODEHDR), &dwWritten, NULL)) { SetHrMsgAndGotoCleanUp(GetLastError()); }
//
// Add Platform
//
CleanUpIfFailedAndSetHr(AddPlatformClass(xmlSpec, iuPlatformInfo));
//
// Add OS Locale information
//
CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, FALSE));
//
// Initialize pszBuff to one NULL character
//
CleanUpFailedAllocSetHrMsg(pszBuff = (TCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR)));
for (int i = 0; i < apszDIID.Size(); i++) { TCHAR* pszTemp; pDIID = apszDIID[i]; //
// NTBUG9#151928 - Log both hardware and compatible IDs of the device that matches lpDeviceInstanceID
//
LOG_Driver(_T("Log device instance with id %s"), pDIID); //
// NOTE: We will ignore MatchingDeviceID's since we won't be called by DevMgr unless there is no installed
// driver. This will allow test harnesses to call this function with valid DeviceInstanceIDs for the
// test client to generate XML.
//
if (CR_SUCCESS == CM_Locate_DevNodeW(&devinst, (LPWSTR) pDIID, 0)) { dwRank = 0; //
// Open a <device> element
//
BSTR bstrDeviceInstance = SysAllocString(pDIID); CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(bstrDeviceInstance, -1, NULL, NULL, NULL, &hDevices)); SafeSysFreeString(bstrDeviceInstance);
//
// Log all the hardware IDs
//
ulLength = 0; if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, NULL, &ulLength, 0)) { CleanUpFailedAllocSetHrMsg(pszTemp = (TCHAR*) HeapReAlloc(GetProcessHeap(), 0, (LPVOID) pszBuff, ulLength)); pszBuff = pszTemp;
if (CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, pszBuff, &ulLength, 0)) { for (TCHAR* pszThisID = pszBuff; *pszThisID; pszThisID += (lstrlen(pszThisID) + 1)) { dwDeviceCount++; LOG_Driver(_T("<hwid/>: %s, rank: %d"), pszThisID, dwRank); bstrThisID = T2BSTR(pszThisID); CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, FALSE, dwRank++, bstrThisID, NULL)); SafeSysFreeString(bstrThisID); } } }
//
// Log all the compatible IDs
//
ulLength = 0; if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, NULL, &ulLength, 0)) { CleanUpFailedAllocSetHrMsg(pszTemp = (TCHAR*) HeapReAlloc(GetProcessHeap(), 0, (LPVOID) pszBuff, ulLength)); pszBuff = pszTemp;
if (CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, pszBuff, &ulLength, 0)) { for (TCHAR* pszThisID = pszBuff; *pszThisID; pszThisID += (lstrlen(pszThisID) + 1)) { dwDeviceCount++; LOG_Driver(_T("<compid/>: %s, rank: %d"), pszThisID, dwRank); bstrThisID = T2BSTR(pszThisID); CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, TRUE, dwRank++, bstrThisID, NULL)); SafeSysFreeString(bstrThisID); } } }
if (HANDLE_NODE_INVALID != hDevices) { xmlSpec.SafeCloseHandleNode(hDevices); } } } //
// Write the XML to the file
//
if (SUCCEEDED(xmlSpec.GetSystemSpecBSTR(&bstrXmlSystemSpec))) { if (0 == WriteFile(hFile, (LPCVOID) OLE2T(bstrXmlSystemSpec), lstrlenW(bstrXmlSystemSpec) * sizeof(TCHAR), &dwWritten, NULL)) { SetHrMsgAndGotoCleanUp(GetLastError()); } } else { fXmlFileError = true; }
CleanUp:
SysFreeString(iuPlatformInfo.bstrOEMManufacturer); SysFreeString(iuPlatformInfo.bstrOEMModel); SysFreeString(iuPlatformInfo.bstrOEMSupportURL);
if (NULL != hFile) { CloseHandle(hFile); }
SafeSysFreeString(bstrXmlSystemSpec); SafeSysFreeString(bstrThisID);
//
// We've already written everything in list, init so we can start over
//
apszDIID.FreeAll(); SafeHeapFree(pszBuff);
//
// Open Help Center only if we have valid xml and one or more devices
//
if (!fXmlFileError && 0 < dwDeviceCount) { DWORD dwLen; LPTSTR pszSECommand = NULL; // INTERNET_MAX_URL_LENGTH
//
// Allocate buffers
//
pszBuff = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); if (NULL == pszBuff) { LOG_ErrorMsg(E_OUTOFMEMORY); DeleteFile(szUniqueFilename); return; }
pszSECommand = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); if (NULL == pszSECommand) { LOG_ErrorMsg(E_OUTOFMEMORY); SafeHeapFree(pszBuff); DeleteFile(szUniqueFilename); return; }
//
// Manually canonicalize second '?' in base string as excaped "%3F"
//
const static TCHAR tszBase[] = _T("hcp://services/layout/xml?definition=hcp://system/dfs/viewmode.xml&topic=hcp://system/dfs/uplddrvinfo.htm%3F");
LOG_Driver(_T("Filename: %s"), szUniqueFilename); //
// Canonicalize the filename once (i.e. ' ' -> %20) into pszBuff
//
dwLen = INTERNET_MAX_URL_LENGTH; if (!InternetCanonicalizeUrl(szUniqueFilename, pszBuff, &dwLen, 0)) { LOG_ErrorMsg(GetLastError()); SafeHeapFree(pszBuff); SafeHeapFree(pszSECommand); DeleteFile(szUniqueFilename); return; }
LOG_Driver(_T("Filename canonicalized once: %s"), pszBuff);
//
// Concatinate canonicalized filename on to end of base reusing tszBuff1
//
// We don't need to check length since we know length of tszBase + MAX_PATH canonicalized
// string won't exceed INTERNET_MAX_URL_LENGTH;
//
// pszSECommand was allocated to be INTERNET_MAX_URL_LENGTH TCHARs above.
hr = StringCchPrintfEx(pszSECommand, INTERNET_MAX_URL_LENGTH, NULL, NULL, MISTSAFE_STRING_FLAGS, _T("%s%s"), tszBase, pszBuff); if (SUCCEEDED(hr)) { LOG_Driver(_T("Opening HelpCenter via Shell Execute: \"%s\""), (LPCTSTR) pszSECommand);
#if defined(UNICODE) || defined(_UNICODE)
LogMessage("%s\"%S\"", SZ_OPENING_HS, pszSECommand); #else
LogMessage("%s\"%s\"", SZ_OPENING_HS, pszSECommand); #endif
//
// Call HelpCenter
//
ShellExecute(NULL, NULL, pszSECommand, NULL, NULL, SW_SHOWNORMAL); } else { LOG_ErrorMsg(hr); }
SafeHeapFree(pszBuff); SafeHeapFree(pszSECommand);
return; } else { //
// Remove the generated file
//
LOG_Driver(_T("fXmlFileError was true or no devices were added - deleting %s"), szUniqueFilename); DeleteFile(szUniqueFilename); }
return;
#endif // UNICODE is defined
}
//
// Currently, this function is not implemented for Whistler or IU (called by V3 AU on WinME
// to support offline driver cache).
//
int WINAPI InternalQueryDetectionFiles( IN HANDLE /* hConnection */, IN void* /* pCallbackParam */, IN PFN_QueryDetectionFilesCallback /* pCallback */ ) { LOG_Block("InternalQueryDetectionFiles");
LOG_ErrorMsg(E_NOTIMPL);
return 0; }
void InternalSetGlobalOfflineFlag(BOOL fOfflineMode) { //
// Called once exclusively by CDM. This property is used
// to maintain backwards compatibility with the XPClient
// V4 version of CDM (single-instance design). See also
// the comments in the exported ShutdownThreads function.
//
// Unfortunately, we can't report errors to CDM, but we check the
// global before dereferencing (except here which has an HRESULT).
//
if (SUCCEEDED(CreateGlobalCDMEngUpdateInstance())) { g_pCDMEngUpdate->m_fOfflineMode = fOfflineMode; } }
|