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

898 lines
25 KiB
C++

//=======================================================================
//
// 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;
}
}