898 lines
25 KiB
C++
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;
|
|
}
|
|
}
|