windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/cdm/cdm.cpp

1155 lines
32 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//=======================================================================
//
// Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
//
// File: cdm.cpp
//
// Owner: YanL
//
// Description:
//
// Functions exported by CDM
//
// DownloadIsInternetAvailable
// OpenCDMContext
// OpenCDMContextEx
// QueryDetectionFiles
// FindMatchingDriver
// DownloadUpdatedFiles
// DetFilesDownloaded
// LogDriverNotFound
// CloseCDMContext
// GetPackage
// InternalQueryDetectionFiles
// InternalFindMatchingDriver
// InternalDetFilesDownloaded
// InternalLogDriverNotFound
//
//=======================================================================
#include <windows.h>
#include <osdet.h>
#include <setupapi.h>
#include <shlwapi.h>
#include <tchar.h>
#include <wustl.h>
#include <log.h>
#include <wuv3cdm.h>
#include <bucket.h>
#include <newtrust.h>
#include <download.h>
#include <diamond.h>
#include <atlconv.h>
#define _ASSERTE(expr) ((void)0)
#include <atlconv.cpp>
#include "cdm.h"
#include "cdmp.h"
#include <drvinfo.h>
#include <cfgmgr32.h>
#include <shellapi.h>
typedef struct _CONTEXTHANDLE
{
bool fCloseConnection; //Tracks if the connection to the internet was opened by CDM.DLL
bool fNeedUpdate; //TRUE if we need to update CDM.DLL when its connection is closed.
TCHAR szSiteServer[MAX_PATH]; //Description server name.
TCHAR szDownloadServer[MAX_PATH]; //Download server name.
} CONTEXTHANDLE, *PCONTEXTHANDLE;
static frozen_array<CONTEXTHANDLE> g_handleArray;
static HMODULE g_hModule;
static bool g_fNeedUpdate; //Flag that indicates that cdm.dll needs updating.
static int GetHandleIndex(IN HANDLE hConnection);
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID /*lpReserved*/
) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_fNeedUpdate = FALSE;
g_hModule = (HMODULE)hModule; // to return to findoem;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
//If we have downloaded a new dll then we need to update it.
//Note: passing a global to a function is bad form as it can
//cause problems. The only reason that I'm doing this is so
//that the UpdateCDMDll API can be moved to other programs
//since this ability to make a dll or exe self updating is
//very usefull.
if (g_fNeedUpdate)
g_fNeedUpdate = !UpdateCdmDll();
break;
}
return TRUE;
}
//This function determines if this client can connect to the internet.
BOOL DownloadIsInternetAvailable(
void
) {
LOG_block("DownloadIsInternetAvailable");
int iDun = GetDUNConnections();
bool bWizard = IsInternetConnectionWizardCompleted();
bool bConnect = IsInternetConnected();
if (!bConnect && iDun <= 0)
{
LOG_error("if (!!bConnect && iDun <= 0) return false");
return false;
}
if (!bWizard)
{
LOG_error("if (!bWizard) return false");
return false;
}
LOG_out("return true");
return true;
}
//This function Opens an internet connection for download. This connection
//context information is tracked though the returned handle.
//This functon returns a handle a CDM file download context if successful or
//NULL if not. If this function fails GetLastError() can be used to return
//the error code indicating the reason for failure.
HANDLE WINAPI OpenCDMContext(
IN HWND /*hwnd*/ //Window handle to use for any UI that needs to be presented.
) {
LOG_block("OpenCDMContext");
return OpenCDMContextEx(TRUE);
}
HANDLE WINAPI OpenCDMContextEx(
IN BOOL fConnectIfNotConnected
) {
LOG_block("OpenCDMContextEx");
//Initialize context handle array entry and mark it as is use.
CONTEXTHANDLE cth;
ZeroMemory(&cth, sizeof(cth));
bool fConnected = IsInternetConnected();
#ifdef _WUV3TEST
if (fConnected)
{
// catalog spoofing
DWORD dwIsInternetConnected = 1;
DWORD dwSize = sizeof(dwIsInternetConnected);
auto_hkey hkey;
if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
RegQueryValueEx(hkey, _T("IsInternetConnected"), 0, 0, (LPBYTE)&dwIsInternetConnected, &dwSize);
}
// only then do normal
if (0 == dwIsInternetConnected)
{
fConnected = false;
}
}
#endif
if (fConnectIfNotConnected || fConnected)
{
//Assume that we do not need to connect to the internet
cth.fCloseConnection = !IsInternetConnected();
//If we are not already connected to the internet and
//we fail in the attempt then we cannot download any
//drivers so quit.
if (InternetAttemptConnect(0) != NO_ERROR)
{
LOG_error("No internet connection");
return 0;
}
TCHAR szSecurityServer[MAX_PATH] = {0};
lstrcpy(szSecurityServer, SZ_SECURITY_SERVER);
/* Test redirect*/{
auto_hkey hkey;
if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate"), 0, KEY_READ, &hkey)) {
DWORD dwSize = sizeof(szSecurityServer);
RegQueryValueEx(hkey, _T("SecurityServer"), 0, 0, (LPBYTE)&szSecurityServer, &dwSize);
}
}
//Connect to and get server context.
CDownload download;
if (download.Connect(szSecurityServer))
{
LOG_out("Connected to SecurityServer '%s'", szSecurityServer);
}
else
{
LOG_error("No connection to SecurityServer '%s'", szSecurityServer);
return 0;
}
//Init download
CDiamond diamond;
if (!diamond.valid()) {
SetLastError(ERROR_GEN_FAILURE);
LOG_error("cannot init diamond");
return 0;
}
// do security url verification and get server locations
if (!ProcessIdent(download, diamond, szSecurityServer, cth.szSiteServer, cth.szDownloadServer))
{
SetLastError(ERROR_ACCESS_DENIED);
LOG_error("invalid identcdm.cab");
return 0;
}
// reconnect fo Site server if we need to
if (0 != lstrcmpi(cth.szSiteServer, szSecurityServer))
{
if (download.Connect(cth.szSiteServer))
{
LOG_out("Connected to SiteServer '%s'", cth.szSiteServer);
}
else
{
LOG_error("No connection to SiteServer '%s'", cth.szSiteServer);
return 0;
}
}
else
{
LOG_out("SiteServer is %s", szSecurityServer);
}
if (!DownloadCdmCab(download, diamond, cth.fNeedUpdate))
{
LOG_error("Failed to download cdm.cab");
return 0;
}
}
return LongToHandle(g_handleArray.add(cth) + 1);
}
//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 DownloadUpdatedFiles(
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, //size of the download path buffer. If this
//buffer is to small to contain the complete
//path and file name no file will be downloaded.
//The PUINT puReguiredSize parameter can be checked
//to determine the size of buffer necessary to
//perform the download.
OUT PUINT puRequiredSize //required lpDownloadPath buffer size. This
//parameter is filled in with the minimum size
//that is required to place the complete path
//file name of the downloaded file. If this
//parameter is NULL no size is returned.
) {
LOG_block("DownloadUpdatedFiles");
int index = GetHandleIndex(hConnection);
if (-1 == index)
{
LOG_error("invalid handle");
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (NULL == puRequiredSize)
{
LOG_error("puRequiredSize == NULL");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//Check and see if the download path is large enough to contain the return
//directory where we will put the download cab files.
TCHAR szTmpPath[MAX_PATH];
int iLengthNeeded = GetDownloadPath(szTmpPath);
if (lpDownloadPath == NULL || iLengthNeeded > (int)uSize)
{
LOG_error("uSize < then needed");
*puRequiredSize = iLengthNeeded;
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
// Declared locally
typedef long (*PFN_GETPACKAGE)(PCONTEXTHANDLE pContextHandle, PDOWNLOADINFO pDownloadInfo, LPTSTR lpDownloadPath);
PFN_GETPACKAGE pfnGetPackage = NULL;//Entry point in cdm.dll that actually performs the download
// If there is cdmnew.dll in system directory use it
auto_hlib hlib = LoadCdmnewDll();
if (hlib.valid())
{
pfnGetPackage = (PFN_GETPACKAGE)GetProcAddress(hlib,"GetPackage");
if (NULL == pfnGetPackage)
{
//if we cannot find our download function we need to return fail and not attempt
//to download the update package.
LOG_error("cannot find function 'GetPackage'");
return FALSE;
}
LOG_out("Calling GetPackage() from cdmnew.dll");
}
else
{
// Declared locally
long GetPackage(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT LPTSTR lpDownloadPath);
pfnGetPackage = GetPackage;
LOG_out("Calling internal GetPackage()");
}
int iError = (pfnGetPackage)(&g_handleArray[index], pDownloadInfo, szTmpPath);
if (iError != NO_ERROR)
{
SetLastError(iError);
return FALSE;
}
*puRequiredSize = iLengthNeeded;
lstrcpyW(lpDownloadPath, T2W(szTmpPath));
return TRUE;
}
//This API closes the internet connection opened with the OpenCDMContext() API.
//If CDM did not open the internet connection this API simply returns. The CDM
//context handle must have been the same handle that was returned from
//the OpenCDMContext() API.
//
//This call cannot fail. If the pConnection handle is invalid this function
//simply ignores it.
VOID WINAPI CloseCDMContext (
IN HANDLE hConnection //CDM Connection handle returned with OpenCDMContext.
) {
LOG_block("CloseCDMContext");
int index = GetHandleIndex(hConnection);
if ( -1 == index)
{
LOG_error("invalid handle");
return;
}
//If CDM.DLL opened this internet connection and if this connection is
//for a modem then we need to close the internet connection. Note:
//the Open context function only sets fCloseConnection for modem
//connections.
if (g_handleArray[index].fCloseConnection)
InternetAutodialHangup(0);
if (g_handleArray[index].fNeedUpdate)
{
//if any dll needs to be updated then
//we set the global update flag. This will
//force cdm.dll to be replaced when the last
//process detaches.
g_fNeedUpdate = true;
}
g_handleArray.remove(index);
}
int WINAPI QueryDetectionFiles(
IN HANDLE hConnection,
IN void* pCallbackParam,
IN PFN_QueryDetectionFilesCallback pCallback
) {
LOG_block("QueryDetectionFiles");
int index = GetHandleIndex(hConnection);
if (-1 == index)
{
LOG_error("invalid handle");
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// Call external/internal implementetion
typedef int (*PFN_InternalQueryDetectionFiles)(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback);
PFN_InternalQueryDetectionFiles pfnInternalQueryDetectionFiles = NULL;
auto_hlib hlib = LoadCdmnewDll();
if (hlib.valid())
{
pfnInternalQueryDetectionFiles = (PFN_InternalQueryDetectionFiles)GetProcAddress(hlib, "InternalQueryDetectionFiles");
if (NULL == pfnInternalQueryDetectionFiles)
{
LOG_error("cannot find function 'InternalQueryDetectionFiles'");
return FALSE;
}
LOG_out("Calling InternalQueryDetectionFiles() from cdmnew.dll");
}
else
{
// Declared locally
int InternalQueryDetectionFiles(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback);
pfnInternalQueryDetectionFiles = InternalQueryDetectionFiles;
LOG_out("Calling internal InternalQueryDetectionFiles()");
}
return (pfnInternalQueryDetectionFiles)(&g_handleArray[index], pCallbackParam, pCallback);
}
void WINAPI DetFilesDownloaded(
IN HANDLE hConnection
) {
LOG_block("DetFilesDownloaded");
int index = GetHandleIndex(hConnection);
if (-1 == index)
{
LOG_error("invalid handle");
return;
}
// Call external/internal implementetion
typedef void (*PFN_InternalDetFilesDownloaded)(IN PCONTEXTHANDLE pContextHandle);
PFN_InternalDetFilesDownloaded pfnInternalDetFilesDownloaded = NULL;
auto_hlib hlib = LoadCdmnewDll();
if (hlib.valid())
{
pfnInternalDetFilesDownloaded = (PFN_InternalDetFilesDownloaded)GetProcAddress(hlib, "InternalDetFilesDownloaded");
if (NULL == pfnInternalDetFilesDownloaded)
{
LOG_error("cannot find function 'InternalDetFilesDownloaded'");
return;
}
LOG_out("Calling InternalDetFilesDownloaded() from cdmnew.dll");
}
else
{
// Declared locally
void InternalDetFilesDownloaded(IN PCONTEXTHANDLE pContextHandle);
pfnInternalDetFilesDownloaded = InternalDetFilesDownloaded;
LOG_out("Calling internal InternalDetFilesDownloaded()");
}
(pfnInternalDetFilesDownloaded)(&g_handleArray[index]);
}
// supports offline logging
// hConnection NOT used at all
// no network connection or osdet.dll needed for languauge, SKU, platform detection
void WINAPI LogDriverNotFound(
IN HANDLE hConnection,
IN LPCWSTR lpDeviceInstanceID,
IN DWORD dwFlags
) {
LOG_block("LogDriverNotFound");
// Call external/internal implementetion
typedef void (*PFN_InternalLogDriverNotFound)(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags);
PFN_InternalLogDriverNotFound pfnInternalLogDriverNotFound = NULL;
CONTEXTHANDLE cth;
ZeroMemory(&cth, sizeof(cth));
auto_hlib hlib = LoadCdmnewDll();
if (hlib.valid())
{
pfnInternalLogDriverNotFound = (PFN_InternalLogDriverNotFound)GetProcAddress(hlib, "InternalLogDriverNotFound");
if (NULL == pfnInternalLogDriverNotFound)
{
LOG_error("cannot find function 'InternalLogDriverNotFound'");
return;
}
LOG_out("Calling InternalLogDriverNotFound() from cdmnew.dll");
}
else
{
// Declared locally
void InternalLogDriverNotFound(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags);
pfnInternalLogDriverNotFound = InternalLogDriverNotFound;
LOG_out("Calling internal InternalLogDriverNotFound()");
}
// pass in dummy contexthandle
(pfnInternalLogDriverNotFound)(&cth, lpDeviceInstanceID, dwFlags);
}
BOOL WINAPI FindMatchingDriver(
IN HANDLE hConnection,
IN PDOWNLOADINFO pDownloadInfo,
OUT PWUDRIVERINFO pWuDriverInfo
) {
LOG_block("FindMatchingDriver");
int index = GetHandleIndex(hConnection);
if (-1 == index)
{
LOG_error("invalid handle");
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// Call external/internal implementetion
typedef BOOL (*PFN_InternalFindMatchingDriver)(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo);
PFN_InternalFindMatchingDriver pfnInternalFindMatchingDriver = NULL;
auto_hlib hlib = LoadCdmnewDll();
if (hlib.valid())
{
pfnInternalFindMatchingDriver = (PFN_InternalFindMatchingDriver)GetProcAddress(hlib,"InternalFindMatchingDriver");
if (NULL == pfnInternalFindMatchingDriver)
{
LOG_error("cannot find function 'InternalFindMatchingDriver'");
return FALSE;
}
LOG_out("Calling InternalFindMatchingDriver() from cdmnew.dll");
}
else
{
// Declared locally
BOOL InternalFindMatchingDriver(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo);
pfnInternalFindMatchingDriver = InternalFindMatchingDriver;
LOG_out("Calling internal InternalFindMatchingDriver()");
}
return (pfnInternalFindMatchingDriver)(&g_handleArray[index], pDownloadInfo, pWuDriverInfo);
}
//This function is called to download the actual package. What happens is that the
//cdm.dll is copied from the server. This dll is then dynamically loaded by the
//DownloadGetUpdatedFiles() API and called. This allows the most recent cdm.dll
//to be used even if the client has an out dated version on their system.
//
//If this function is successfull then it returns NO_ERROR. If the case of a
//failure this function returns an error code.
long GetPackage(
IN PCONTEXTHANDLE pContextHandle, //Pointer Context handle structure that contains the server and dll information needed to perform the download.
IN PDOWNLOADINFO pDownloadInfo, //download information structure describing package to be read from server
OUT LPTSTR lpDownloadPath //Poitner to local directory on the client computer system where the downloaded files are to be stored.
) {
LOG_block("GetPackage");
USES_CONVERSION;
SHelper helper;
//
// NTRAID#NTBUG9-185297-2000/11/21-waltw Fixed: bufBucket must have same scope as SHelper
//
byte_buffer bufBucket;
DWORD dwError = PrepareCatalog(pContextHandle->szSiteServer, helper);
if (NO_ERROR != dwError)
{
SetLastError(dwError);
return FALSE;
}
//Clear out any files that might be in the temp download directory.
if (!DeleteNode(lpDownloadPath))
{
LOG_out("DeleteNode(%s) failed last error %d", lpDownloadPath, GetLastError());
}
if (!CreateDirectory(lpDownloadPath, NULL))
{
LOG_out("CreateDirectory(%s) failed last error %d", lpDownloadPath, GetLastError());
}
bool fPlist = (
NULL != pDownloadInfo->lpHardwareIDs &&
0 == lstrcmpiW(L"3FBF5B30-DEB4-11D1-AC97-00A0C903492B", pDownloadInfo->lpHardwareIDs)
);
// Get to and from information
TCHAR szCabLocalFile[MAX_PATH];
GetWindowsUpdateDirectory(szCabLocalFile);
if (fPlist) {
TCHAR szCabServerFile[MAX_PATH];
wsprintf(szCabServerFile, _T("%d_%#08x.plist"), helper.enPlatform, helper.dwLangID);
LOG_out("getting PLIST %s", szCabServerFile);
PathAppend(szCabLocalFile, szCabServerFile);
// Now we can say that we are ready
if (!helper.download.Copy(szCabServerFile, szCabLocalFile))
{
LOG_error("%s failed to download", szCabServerFile);
return ERROR_FILE_NOT_FOUND;
}
}
else
{
TCHAR szCabFileTitle[MAX_PATH];
if (!FindUpdate(pDownloadInfo, helper, bufBucket))
{
LOG_error("no update has been found");
return ERROR_FILE_NOT_FOUND;
}
LOG_out("PUID %d is found", helper.puid);
CDownload downloadCabpool;
if (downloadCabpool.Connect(pContextHandle->szDownloadServer))
{
LOG_out("Connected to DownloadServer '%s'", pContextHandle->szDownloadServer);
}
else
{
LOG_error("No connection to DownloadServer '%s'", pContextHandle->szDownloadServer);
return ERROR_GEN_FAILURE;
}
TCHAR szCabServerFile[MAX_PATH];
lstrcpy(szCabServerFile, _T("CabPool/"));
lstrcat(szCabServerFile, A2T(helper.DriverMatchInfo.pszCabFileTitle));
PathAppend(szCabLocalFile, A2T(helper.DriverMatchInfo.pszCabFileTitle));
// Now we can say that we are ready
if (!downloadCabpool.Copy(szCabServerFile, szCabLocalFile))
{
LOG_error("%s failed to download", szCabServerFile);
URLPingReport(helper, URLPING_FAILED);
return ERROR_FILE_NOT_FOUND;
}
// Verify if it's not webntprn.cab
HRESULT hr = VerifyFile(szCabLocalFile, FALSE);
if (FAILED(hr))
{
LOG_error("signature verification failed");
DeleteFile(szCabLocalFile);
URLPingReport(helper, URLPING_FAILED);
return hr;
}
}
TCHAR szDownloadFiles[MAX_PATH];
lstrcpy(szDownloadFiles, lpDownloadPath);
PathAppend(szDownloadFiles, _T("*"));
if (!helper.diamond.Decompress(szCabLocalFile, szDownloadFiles))
{
LOG_error("Decompress failed");
if (!fPlist)
URLPingReport(helper, URLPING_FAILED);
return ERROR_FILE_NOT_FOUND;
}
LOG_out("Download to %s completed OK", lpDownloadPath);
DeleteFile(szCabLocalFile);
if (!fPlist)
URLPingReport(helper, URLPING_SUCCESS);
return S_OK;
}
static void UrlAppend(LPTSTR pszURL, LPCTSTR pszPath)
{
if ('/' != pszURL[lstrlen(pszURL) - 1])
lstrcat(pszURL, _T("/"));
lstrcat(pszURL, pszPath);
}
inline bool IsNewer(
IN LPCTSTR szFileName1,
IN LPCTSTR szFileName2
) {
LOG_block("IsNewer");
auto_hfile hFile1 = CreateFile(szFileName1, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hFile1.valid())
{
LOG_error("CreateFile(%s, ...) failed, error %d", szFileName1, GetLastError());
return true;
}
auto_hfile hFile2 = CreateFile(szFileName2, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hFile2.valid())
{
LOG_error("CreateFile(%s, ...) failed, error %d", szFileName2, GetLastError());
return false;
}
FILETIME ft1;
if (!GetFileTime(hFile1, NULL, NULL, &ft1))
{
LOG_error("GetFileTime(%s, ...) failed, error %d", szFileName1, GetLastError());
return true;
}
FILETIME ft2;
if (!GetFileTime(hFile2, NULL, NULL, &ft2))
{
LOG_error("GetFileTime(%s, ...) failed, error %d", szFileName2, GetLastError());
return false;
}
return CompareFileTime(&ft1, &ft2) < 0;
}
void DoCallback(
IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback,
SHelper& helper, LPCTSTR pszSiteServer, LPCTSTR pszFileTitle, bool fInCatalog = true
) {
USES_CONVERSION;
TCHAR szCatalog[32];
wsprintf(szCatalog, _T("%d"), helper.puidCatalog);
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
lstrcpy(szURL, pszSiteServer);
if (fInCatalog)
UrlAppend(szURL, szCatalog);
UrlAppend(szURL, pszFileTitle);
TCHAR szLocalFile[MAX_PATH];
GetWindowsUpdateDirectory(szLocalFile);
PathAppend(szLocalFile, pszFileTitle);
pCallback(pCallbackParam, T2W(szURL), T2W(szLocalFile));
}
int InternalQueryDetectionFiles(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback)
{
LOG_block("InternalQueryDetectionFiles");
SHelper helper;
DWORD dwError = PrepareCatalog(pContextHandle->szSiteServer, helper);
if (NO_ERROR != dwError)
{
SetLastError(dwError);
return -1;
}
#if 0
// Get CDM inventory
TCHAR szPath[MAX_PATH];
wsprintf(szPath, _T("%d/%d.cab"), helper.puidCatalog, helper.puidCatalog);
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
lstrcpy(szURL, pContextHandle->szSiteServer);
UrlAppend(szURL, szPath);
GetWindowsUpdateDirectory(szPath);
PathAppend(szPath, _T("buckets.cab"));
pCallback(pCallbackParam, T2W(szURL), T2W(szPath));
return 1;
#else
// Get CDM inventory
TCHAR szPath[MAX_PATH];
wsprintf(szPath, _T("%d/inventory.cdm"), helper.puidCatalog);
byte_buffer bufInventory;
if (!DownloadToBuffer(helper, szPath, bufInventory))
{
LOG_error("Dowload inventory failed");
return -1;
}
//Here we need a trick to determine if we need to do anything: we do if inventory.cdm is a newer then inventory.cdm.last
GetWindowsUpdateDirectory(szPath);
PathAppend(szPath, _T("inventory.cdm"));
TCHAR szPathLast[MAX_PATH];
lstrcpy(szPathLast, szPath);
lstrcat(szPathLast, _T(".last"));
if (!IsNewer(szPathLast, szPath))
{
LOG_out("inventory.cdm is up to date");
return 0;
}
CopyFile(szPath, szPathLast, FALSE);
PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)bufInventory;
int nCount = 0;
DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, _T("oeminfo.bin"), false);
nCount ++;
DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, _T("bitmask.cdm"));
nCount ++;
for (ULONG ulHashIndex = 0; ulHashIndex < pHashTable->hdr.iTableSize; ulHashIndex ++)
{
if(GETBIT(pHashTable->pData, ulHashIndex))
{
TCHAR szTitle[16];
wsprintf(szTitle, _T("%d.bkf"), ulHashIndex);
DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, szTitle);
nCount ++;
}
}
return nCount;
#endif
}
void InternalDetFilesDownloaded(IN PCONTEXTHANDLE pContextHandle)
{
LOG_block("InternalDetFilesDownloaded");
#if 0
TCHAR szPath[MAX_PATH];
GetWindowsUpdateDirectory(szPath);
PathAppend(szPath, _T("buckets.cab"));
CDiamond diamond;
diamond.Decompress(szPath, _T("*"));
#endif
}
// pContextHandle not used.
// dwFlags could be either 0 or BEGINLOGFLAG
void InternalLogDriverNotFound(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags)
{
LOG_block("InternalLogDriverNotFound");
LOG_out("DeviceInstanceID is %s", lpDeviceInstanceID);
using std::vector;
DWORD bytes;
//auto_pointer<IDrvInfo> pDrvInfo;
tchar_buffer bufText;
TCHAR tszFilename[MAX_PATH];
TCHAR tszUniqueFilename[MAX_PATH];
TCHAR tszBuffer[32];
DEVINST devinst;
HRESULT hr = E_FAIL;
bool fXmlFileError = false;
static vector<WCHAR*> vDIDList; //device instance id list
LPWSTR pDID = NULL; //Device Instance ID
FILE * fOut = NULL; //for XML file
SHelper helper;
HANDLE hFile = NULL;
lstrcpy(tszFilename, _T("")); //initialize tszFilename
if (lpDeviceInstanceID != NULL)
{ //append the new device instance id into internal list
pDID = (LPWSTR) malloc((wcslen(lpDeviceInstanceID)+1) * sizeof(WCHAR));
if (NULL == pDID)
{
LOG_error("memory allocation failed for new DeviceInstanceID");
}
else
{
lstrcpyW(pDID, lpDeviceInstanceID);
vDIDList.push_back(pDID);
LOG_out("new DeviceInstanceID added to internal list");
}
}
if (0 == (dwFlags & BEGINLOGFLAG) || 0 == vDIDList.size())
{ // not last log request or nothing to log
LOG_out("Won't log to hardware_XXX.xml");
return;
}
GetWindowsUpdateDirectory(tszFilename);
hr = GetUniqueFileName(tszFilename,tszUniqueFilename, MAX_PATH, hFile);
if (S_OK != hr)
{
LOG_error("fail to get unique file name");
fXmlFileError = true;
goto CloseXML;
}
lstrcat(tszFilename, tszUniqueFilename);
CloseHandle(hFile);
fOut = _tfopen(tszFilename, _T("wb"));
if (! fOut)
{
LOG_error("_tfopen failed");
fXmlFileError = true;
DeleteFile(tszFilename);
goto CloseXML;
}
LOG_out("Logging to %s", tszFilename);
// Don't need to get langID and platformID from catalog
// get it offline using osdet.dll
if (S_OK != ProcessOsdetOffline(helper))
{
LOG_error("platform and language detection failed");
fXmlFileError = true;
goto CloseXML;
}
_tstrdate(tszBuffer);
#ifdef _UNICODE
fwprintf(fOut, _T("%c"), (int) 0xFEFF);
#else
#error _UNICODE must be defined for InternalLogDriverNotFound
#endif
TCHAR tszSKU[SKU_STRING_MAX_LENGTH];
hr = GetSKUString(tszSKU, SKU_STRING_MAX_LENGTH);
if (S_OK != hr)
{
LOG_error("Fail to get SKU string");
fXmlFileError = true;
goto CloseXML;
}
if (0 > _ftprintf(fOut, _T("<?xml version=\"1.0\"?>\r\n<inventory date=\"%s\" locale=\"%p\" platform=\"%d\" sku=\"%s\">\r\n"), tszBuffer, helper.dwLangID, helper.enPlatform, tszSKU))
{
fXmlFileError = true;
goto CloseXML;
}
for (int i = 0; i < vDIDList.size(); i++)
{
pDID = vDIDList[i];
//
// NTBUG9#151928 - Log both hardware and compatible IDs of the device that matches lpDeviceInstanceID
//
LOG_out("Log device instance with id %s", pDID);
if (CR_SUCCESS == CM_Locate_DevNode(&devinst, (LPWSTR) pDID, 0))
{
if (0 > _ftprintf(fOut, _T("\t<device>\r\n")))
{
fXmlFileError = true;
goto CloseXML;
}
//
// Log device description
//
ULONG ulLength = 0;
if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_DEVICEDESC, NULL, NULL, &ulLength, 0))
{
bufText.resize(ulLength);
if (bufText.valid() &&
CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_DEVICEDESC, NULL, bufText, &ulLength, 0))
{
if (0 > _ftprintf(fOut, _T("\t\t<description><![CDATA[%s]]></description>\r\n"), (LPCTSTR) bufText))
{
fXmlFileError = true;
goto CloseXML;
}
}
}
//
// Log all the hardware IDs
//
ulLength = 0;
if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, NULL, &ulLength, 0))
{
bufText.resize(ulLength);
if (bufText.valid() &&
CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, bufText, &ulLength, 0))
{
for (TCHAR* pszNextID = (TCHAR*) bufText; *pszNextID; pszNextID += (lstrlen(pszNextID) + 1))
{
if (0 > _ftprintf(fOut, _T("\t\t<hwid><![CDATA[%s]]></hwid>\r\n"), (LPCTSTR) pszNextID))
{
fXmlFileError = true;
goto CloseXML;
}
}
}
}
//
// Log all the compatible IDs
//
ulLength = 0;
if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, NULL, &ulLength, 0))
{
bufText.resize(ulLength);
if (bufText.valid() &&
CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, bufText, &ulLength, 0))
{
for (TCHAR* pszNextID = (TCHAR*) bufText; *pszNextID; pszNextID += (lstrlen(pszNextID) + 1))
{
if (0 > _ftprintf(fOut, _T("\t\t<compid><![CDATA[%s]]></compid>\r\n"), (LPCTSTR) pszNextID))
{
fXmlFileError = true;
goto CloseXML;
}
}
}
}
if (0 > _ftprintf(fOut, _T("\t</device>\r\n")))
{
fXmlFileError = true;
goto CloseXML;
}
}
} //for
if(0 > _ftprintf(fOut, _T("</inventory>\r\n")))
{
fXmlFileError = true;
}
CloseXML:
if (fOut != NULL) fclose(fOut);
for (int i = 0; i < vDIDList.size(); i++)
{//free memory
free(vDIDList[i]);
}
vDIDList.clear();
//
// Open Help Center only if we have valid xml
//
if (!fXmlFileError)
{
// open help center
const static TCHAR szBase[] = _T("hcp://services/layout/contentonly?topic=hcp://system/dfs/uplddrvinfo.htm%3f"); //hardcode '?' escaping
tchar_buffer tchCName(MAX_PATH); //file name canonicalized once
tchar_buffer tchC2Name(INTERNET_MAX_URL_LENGTH); //file name canonicalized twice
tchar_buffer tchFinalUrl;
DWORD dwLen = 0;
BOOL fBufferResized = FALSE;
GetWindowsUpdateDirectory(tszFilename);
lstrcat(tszFilename, tszUniqueFilename);
LOG_out("Canonicalize %s", tszFilename);
if (FAILED(CdmCanonicalizeUrl(tszFilename, tchCName, MAX_PATH, 0)))
{
goto CleanUp;
}
LOG_out("File name canonicalized %s", (LPTSTR) tchCName);
LOG_out("Canonicalize file name %s AGAIN", (LPTSTR)tchCName);
if (FAILED(CdmCanonicalizeUrl((LPCTSTR)tchCName, tchC2Name, INTERNET_MAX_URL_LENGTH, ICU_ENCODE_PERCENT)))
{
goto CleanUp;
}
LOG_out("File name canonicalized twice %s", (LPTSTR)tchC2Name);
//need one extra character space
//for the ending null
tchFinalUrl.resize(lstrlen(szBase) + lstrlen((LPCTSTR) tchC2Name) + 1);
if (!tchFinalUrl.valid())
{
LOG_error("Out of memory for FinalUrl buffer");
goto CleanUp;
}
wsprintf(tchFinalUrl, _T("%s%s"), szBase, (LPCTSTR) tchC2Name);
LOG_out("Opening HelpCenter: \"%s\"", (LPCTSTR) tchFinalUrl);
ShellExecute(NULL, NULL, (LPCTSTR) tchFinalUrl, NULL, NULL, SW_SHOWNORMAL);
return; //keep the file and return
}
//remove the file generated
CleanUp:
if (fOut != NULL)
{
DeleteFile(tszFilename);
fOut = NULL;
}
return;
}
BOOL InternalFindMatchingDriver(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo)
{
LOG_block("InternalFindMatchingDriver");
bool fConnected = IsInternetConnected();
#ifdef _WUV3TEST
if (fConnected)
{
// catalog spoofing
DWORD dwIsInternetConnected = 1;
DWORD dwSize = sizeof(dwIsInternetConnected);
auto_hkey hkey;
if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
RegQueryValueEx(hkey, _T("IsInternetConnected"), 0, 0, (LPBYTE)&dwIsInternetConnected, &dwSize);
}
// only then do normal
if (0 == dwIsInternetConnected)
{
fConnected = false;
}
}
#endif
SHelper helper;
//
// NTRAID#NTBUG9-185297-2000/11/21-waltw Fixed: bufBucket must have same scope as SHelper
//
byte_buffer bufBucket;
DWORD dwError = PrepareCatalog(fConnected ? pContextHandle->szSiteServer : NULL, helper);
if (NO_ERROR != dwError)
{
SetLastError(dwError);
return FALSE;
}
if (!FindUpdate(pDownloadInfo, helper, bufBucket))
{
LOG_out("NO UPDATE IS FOUND");
return FALSE;
}
LOG_out("PUID %d IS FOUND", helper.puid);
// Fill out info
if (
0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszHardwareID, -1, pWuDriverInfo->wszHardwareID, HWID_LEN) ||
0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszDescription, -1, pWuDriverInfo->wszDescription, LINE_LEN) ||
0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszMfgName, -1, pWuDriverInfo->wszMfgName, LINE_LEN) ||
0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszProviderName, -1, pWuDriverInfo->wszProviderName, LINE_LEN) ||
0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszDriverVer, -1, pWuDriverInfo->wszDriverVer, LINE_LEN)
) {
LOG_error("MultiByteToWideChar failed");
return FALSE;
}
return TRUE;
}
//This API gets the context handle array index from a connection handle.
//The connection context handle is checked if found invalid then -1 is
//returned. Otherwise the index that this handle references is returned.
int GetHandleIndex(
IN HANDLE hConnection //CDM Connect handle
) {
int index = HandleToLong(hConnection) - 1;
//If handle is invalid or not in use then return as nothing to do.
if (!g_handleArray.valid_index(index))
return -1;
return index;
}
// for findoem
HMODULE GetModule()
{
return g_hModule;
}