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

711 lines
22 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//=======================================================================
//
// Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
//
// File: ccdm.cpp
//
// Owner: YanL
//
// Description:
//
// CDM support from the site
//
//=======================================================================
#include "stdafx.h"
#include <winspool.h>
#include <setupapi.h>
#include <wustl.h>
#define LOGGING_LEVEL 1
#include <log.h>
#include <wuv3sys.h>
#include <drvinfo.h>
#include <ccdm.h>
#include <findoem.h>
#include <shlwapi.h>
#include "printers.h"
static DWORD OpenReinstallKey(HKEY* phkeyReinstall);
static DWORD GetReinstallString(LPCTSTR szHwID, tchar_buffer& bchReinstallString);
static DWORD DeleteReinstallKey(LPCTSTR szHwID);
bool DownloadToBuffer(
IN LPCTSTR szPath,
IN CWUDownload *pDownload, //pointer to internet server download class.
IN CDiamond *pDiamond, //pointer to diamond de-compression class.
OUT byte_buffer& bufOut
) {
byte_buffer bufTmp;
if (!pDownload->MemCopy(szPath, bufTmp))
return false;
if (pDiamond->IsValidCAB(bufTmp))
{
if (!pDiamond->Decompress(bufTmp, bufOut))
return false;
}
else
{
//else the oem table is in uncompressed format.
bufOut << bufTmp;
}
return true;
}
//Note: This method works specifically with a CCdm class. The CCdm class contains
//the returned inventory item array. So if multiple threads are used then
//multiple instances of the CCdm class will be required. This should not ever be a
//problem since we do not ever plan or have any reason to do single instance groveling
//for device drivers.
//This method adds CDM records to an internal CDM inventory list. The CCatalog
//prune method performs the final copy and insertion of these records into the
//final inventory catalog.
void CCdm::CreateInventoryList(
IN CBitmask *pBm, //bitmask to be used to prune the inventory list.
IN CWUDownload *pDownload, //pointer to internet server download class.
IN CDiamond *pDiamond, //pointer to diamond de-compression class.
IN PUID puidCatalog, //puid identifier of catalog where device drivers are stored.
IN PBYTE pOemInfoTable //Pointer OEM info table that OEM detection needs.
) {
LOG_block("CCdm::CreateInventoryList");
USES_CONVERSION;
// Start
m_iCDMTotalItems = 0;
//check input arguments
if (NULL == pBm || NULL == pDownload || NULL == pDiamond)
{
return;
}
//First prune list based on bitmask
//This is accomplished by anding the appropriate bitmasks to form a global bitmask.
DWORD langid = GetMachineLangDW();
PBYTE pBitmaskBits = pBm->GetClientBits(GetMachinePnPID(pOemInfoTable), langid);
if (NULL == pBitmaskBits)
{
return;
}
{
//Note: a cdm catalog cannot have a 0 puid since that the inventory.plt will
//never have a device driver insertion record. So this function will not be
//called for the inventory.plt catalog.
TCHAR szPath[MAX_PATH];
wsprintf(szPath, _T("%d/inventory.cdm"), puidCatalog);
if (!DownloadToBuffer(szPath, pDownload, pDiamond, m_bufInventory))
throw HRESULT_FROM_WIN32(GetLastError());
}
vector<SCdmItem> aitemUpdates;
/* Regular drivers */ {
CDrvInfoEnum DrvInfoEnum;
auto_pointer<IDrvInfo> pDrvInfo;
while (DrvInfoEnum.GetNextDrvInfo(&pDrvInfo))
{
tchar_buffer bufDeviceInstanceID;
if (!pDrvInfo->GetDeviceInstanceID(bufDeviceInstanceID))
{
LOG_error("!pDrvInfo->GetDeviceInstanceID()");
continue;
}
LOG_block(T2A(bufDeviceInstanceID));
if (pDrvInfo->IsPrinter())
{
LOG_error("!pDrvInfo->IsPrinter()");
continue;
}
tchar_buffer bufHardwareIDs;
if (!pDrvInfo->GetAllHardwareIDs(bufHardwareIDs))
{
LOG_error("!pDrvInfo->GetAllHardwareIDs()");
continue;
}
tchar_buffer bufMatchingDeviceId;
pDrvInfo->GetMatchingDeviceId(bufMatchingDeviceId); // It's OK not to get it
// #ifdef _WUV3TEST
if (pDrvInfo.valid() && pDrvInfo->HasDriver())
{
if (bufMatchingDeviceId.valid())
LOG_out("driver installed on MatchingDeviceId %s", (LPCTSTR)bufMatchingDeviceId);
else
LOG_error("driver installed, but HWID is not available");
}
else
{
if (bufMatchingDeviceId.valid())
LOG_error("driver is not installed, but MatchingDeviceId is %s", (LPCTSTR)bufMatchingDeviceId);
else
LOG_out("no driver installed");
}
// #endif
// Updates
bool fMoreSpecific = true;
for (LPCTSTR szHardwareId = bufHardwareIDs; fMoreSpecific && *szHardwareId; szHardwareId += lstrlen(szHardwareId) + 1)
{
// MatchingDeviceID is the last one to pay attention to
fMoreSpecific = !bufMatchingDeviceId.valid() || 0 != lstrcmpi(szHardwareId, bufMatchingDeviceId);
ULONG ulHashIndex = IsInMap(szHardwareId);
if (-1 == ulHashIndex)
continue;
//else download the server bucket file
byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
FILETIME ftDriverInstalled = {0,0};
if (!fMoreSpecific)
{
// Then it has to have a driver - Matching device ID is set
if (!pDrvInfo->GetDriverDate(ftDriverInstalled))
{
LOG_error("!pDrvInfo->GetDriverDate(ftDriverInstalled)");
break;
}
}
DRIVER_MATCH_INFO DriverMatchInfo;
PUID puid = CDM_FindUpdateInBucket(szHardwareId, fMoreSpecific ? NULL : &ftDriverInstalled, bufBucket, bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
// See if it's being added already
if (0 == puid)
{
LOG_out("CDM_FindUpdateInBucket returns 0");
continue;
}
// something has been found
AddItem(aitemUpdates, puid, bufMatchingDeviceId.valid() ? CDM_UPDATED_DRIVER : CDM_NEW_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer));
break;
}
// Installed
if (bufMatchingDeviceId.valid())
{
LPCTSTR szHardwareId = bufMatchingDeviceId;
tchar_buffer bchReinstallString;
if (NO_ERROR != GetReinstallString(szHardwareId, bchReinstallString))
{
LOG_out("No reinstall string for %s", szHardwareId);
continue;
}
ULONG ulHashIndex = IsInMap(szHardwareId);
if (-1 == ulHashIndex)
continue;
//else download the server bucket file
byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
DRIVER_MATCH_INFO DriverMatchInfo;
PUID puid = CDM_FindInstalledInBucket(pDrvInfo, szHardwareId, bufBucket,
bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
// See if it's being added already
if (0 == puid)
{
LOG_out("CDM_FindInstalledInBucket returns 0");
continue;
}
// something has been found
AddItem(aitemUpdates, puid, CDM_CURRENT_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer));
}
} // while (DrvInfoEnum.GetNextDrvInfo(&pDrvInfo))
}
/* Printer drivers */ {
CPrinterDriverInfoArray ainfo;
for(DWORD dwDriverIdx = 0; dwDriverIdx < ainfo.GetNumDrivers(); dwDriverIdx ++)
{
LPDRIVER_INFO_6 pinfo = ainfo.GetDriverInfo(dwDriverIdx);
if (NULL == pinfo)
continue;
tchar_buffer bufHardwareID;
if (!ainfo.GetHardwareID(pinfo, bufHardwareID))
continue;
ULONG ulHashIndex = IsInMap(bufHardwareID);
if (-1 == ulHashIndex)
continue;
//else download the server bucket file
byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
DRIVER_MATCH_INFO DriverMatchInfo;
PUID puid = CDM_FindUpdateInBucket(bufHardwareID, &(pinfo->ftDriverDate), bufBucket,
bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
if (0 == puid)
{
LOG_out("CDM_FindInstalledInBucket returns 0");
continue;
}
AddItem(aitemUpdates, puid, CDM_UPDATED_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer), pinfo->pName, ainfo.GetArchitecture(pinfo));
}
}
//Do converson
AddInventoryRecords(aitemUpdates);
}
// Check if given PNPID is current hash table mapping.
//if PnpID is in hash table then return index
ULONG CCdm::IsInMap(
IN LPCTSTR pHwID //hardware id to be retrieved
) {
LOG_block("CCdm::IsInMap");
// check if the member variable m_bufInventory is not NULL and the input argument is not NULL
if (NULL == (PCDM_HASHTABLE)(LPBYTE)m_bufInventory || NULL == pHwID)
{
return -1;
}
PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)m_bufInventory;
ULONG ulTableEntry = CDM_HwID2Hash(pHwID, pHashTable->hdr.iTableSize);
if(GETBIT(pHashTable->pData, ulTableEntry))
{
LOG_out("%s (hash %d) is found", pHwID, ulTableEntry);
return ulTableEntry;
}
LOG_out("%s (hash %d) is not found", pHwID, ulTableEntry);
return -1;
}
//Reads and initializes a compressed CDM bucket file from an internet server.
//Returnes the array index where the bucket file is stored.
byte_buffer& CCdm::ReadBucketFile(
IN CWUDownload *pDownload, //pointer to internet server download class.
IN CDiamond *pDiamond, //pointer to diamond de-compression class.
IN PUID puidCatalog, //PUID id of catalog for which cdm hash table is to be retrieved.
IN ULONG ulHashIndex //Hash table index of bucket file to be retrieved
) {
LOG_block("CCdm::ReadBucketFile");
// If it there return it
for(int i = 0; i < m_aBuckets.size(); i ++)
{
if (ulHashIndex == m_aBuckets[i].first)
return m_aBuckets[i].second;
}
// download it
byte_buffer bufBucket;
{
TCHAR szPath[MAX_PATH];
wsprintf(szPath, _T("%d/%d.bkf"), puidCatalog, ulHashIndex);
if (!DownloadToBuffer(szPath, pDownload, pDiamond, bufBucket))
throw HRESULT_FROM_WIN32(GetLastError());
}
m_aBuckets.push_back(my_pair(ulHashIndex, bufBucket));
return m_aBuckets[m_aBuckets.size() - 1].second;
}
PINVENTORY_ITEM CCdm::ConvertCDMItem(
int index //Index of cdm record to be converted
) {
if ( index < 0 || index >= m_iCDMTotalItems )
return NULL;
// this is a no-op, we just hand off the existing pointer
return m_items[index];
}
// add detected item to a list
void CCdm::AddItem(
vector<SCdmItem>& acdmItem,
PUID puid,
enumDriverDisposition fDisposition,
LPCTSTR szHardwareId,
LPCTSTR szDriverVer,
LPCTSTR szPrinterDriverName /*= NULL*/,
LPCTSTR szArchitecture /*= NULL*/
) {
LOG_block("CCdm::AddItem");
LOG_out("%s PUID = %d, HardwareId = %s", szPrinterDriverName ? _T("Prt") : _T("Dev"), puid, szHardwareId);
// First check if this puid is included
bool fNew = true;
for (int nItem = 0; nItem < acdmItem.size(); nItem ++)
{
if ((acdmItem[nItem].puid == puid) && (acdmItem[nItem].fInstallState == fDisposition))
{
fNew = false;
break;
}
}
if (fNew)
{ // new item;
LOG_out("Adding as a new item");
acdmItem.push_back(SCdmItem());
SCdmItem& item = acdmItem.back();
item.puid = puid;
item.fInstallState = fDisposition;
item.sDriverVer = szDriverVer;
if (szArchitecture)
item.sArchitecture = szArchitecture;
if (szPrinterDriverName)
item.sPrinterDriverName = szPrinterDriverName;
item.bufHardwareIDs.resize(lstrlen(szHardwareId) + 2);
if(!item.bufHardwareIDs.valid())
return; //out of memory
lstrcpy(item.bufHardwareIDs, szHardwareId);
((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 2] = 0;
((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 1] = 0;
}
else
{
SCdmItem& item = acdmItem[nItem];
// check if Hardware ID is already included
for (LPCTSTR szCurHardwareId = acdmItem[nItem].bufHardwareIDs; *szCurHardwareId; szCurHardwareId += lstrlen(szCurHardwareId) + 1)
{
if (0 == lstrcmpi(szCurHardwareId, szHardwareId))
{
// Got It
LOG_out("Already present");
return;
}
}
LOG_out("Appending hardware ID");
int cnOldSize = item.bufHardwareIDs.size();
item.bufHardwareIDs.resize(cnOldSize + lstrlen(szHardwareId) + 1);
if(!item.bufHardwareIDs.valid())
return; //out of memory
lstrcpy((LPTSTR)item.bufHardwareIDs + cnOldSize - 1, szHardwareId);
((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 2] = 0;
((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 1] = 0;
}
}
//This function is used to create a CDM inventory record. This record is initialized with
//the CDM bucket information.
void CCdm::AddInventoryRecords(
vector<SCdmItem>& acdmItem
) {
LOG_block("CCdm::AddInventoryRecords");
for (int nItem = 0; nItem < acdmItem.size(); nItem ++)
{
PINVENTORY_ITEM pItem = 0;
try
{
//allocate and initialize a new catalog item
//note that this memory is never freed by this class
//We rely on the fact that this pointer is going to be
//handed off (in ConvertCDMItem()) and someone else will free it.
pItem = (PINVENTORY_ITEM)V3_malloc(sizeof(INVENTORY_ITEM) + sizeof(WU_INV_FIXED) + sizeof(WU_VARIABLE_FIELD));
//we need to set these up by the inventory catalog copy and insert routine.
pItem->pd = NULL;
//first setup the fixed part of the inventory item
pItem->pf = (PWU_INV_FIXED)(((PBYTE)pItem) + sizeof(INVENTORY_ITEM));
//We need to fix the record type here as it has to be correct before it is
//inserted into the inventory list.
if (acdmItem[nItem].sPrinterDriverName.length())
{ //printer
pItem->pf->d.type = SECTION_RECORD_TYPE_PRINTER;
pItem->recordType = WU_TYPE_RECORD_TYPE_PRINTER;
}
else
{ // pnp device
pItem->pf->d.type = SECTION_RECORD_TYPE_DRIVER_RECORD;
pItem->recordType = WU_TYPE_CDM_RECORD; //Corporate catalog device driver
}
pItem->pf->d.puid = acdmItem[nItem].puid;
pItem->pf->d.flags = 0;
pItem->pf->d.link = 0;
//set up the state of the item. This used to take place in ConvertCDMItem()
//initialize and store the internal item state structure
pItem->ps = (PWU_INV_STATE)V3_malloc(sizeof(WU_INV_STATE));
//translate the internal CDM item states to the public WUV3IS item
//states.
switch (acdmItem[nItem].fInstallState)
{
case CDM_NEW_DRIVER:
pItem->ps->state = WU_ITEM_STATE_INSTALL;
break;
case CDM_UPDATED_DRIVER:
pItem->ps->state = WU_ITEM_STATE_UPDATE;
break;
case CDM_CURRENT_DRIVER:
pItem->ps->state = WU_ITEM_STATE_CURRENT;
break;
default:
pItem->ps->state = WU_ITEM_STATE_UNKNOWN;
};
pItem->ps->bChecked = FALSE;
pItem->ps->bHidden = FALSE;
pItem->ps->dwReason = WU_STATE_REASON_NONE;
//setup the variable part of the item. In the main catalog inventory case this
//is all that we need to do. In the case of the corporate catalog we will need
//to add one more variable field. This field is the CDM bucket hashIndex id.
//This allows the corporate catalog to perform defered detection on device
//driver records.
//We need to add the ending variable size record since the list needs to
//be initialized before AddVariableSizeField() will work.
pItem->pv = (PWU_VARIABLE_FIELD)((PBYTE)pItem + sizeof(INVENTORY_ITEM) + sizeof(WU_INV_FIXED));
pItem->pv->id = WU_VARIABLE_END;
pItem->pv->len = sizeof(WU_VARIABLE_FIELD);
//Add in the needed variable field items. (Note: Only variable detection
//items are placed in the catalog inventory list to mimimize download size).
PWU_VARIABLE_FIELD pVf = CreateVariableField(WU_CDM_HARDWARE_ID, (PBYTE)(LPTSTR)acdmItem[nItem].bufHardwareIDs,
acdmItem[nItem].bufHardwareIDs.size() * sizeof(TCHAR));
AddVariableSizeField(&pItem, pVf);
V3_free(pVf);
pVf = CreateVariableField(WU_VARIABLE_DRIVERVER, (PBYTE)(LPTSTR)acdmItem[nItem].sDriverVer.c_str(),
(acdmItem[nItem].sDriverVer.length() + 1) * sizeof(TCHAR));
AddVariableSizeField(&pItem, pVf);
V3_free(pVf);
if (CDM_CURRENT_DRIVER == acdmItem[nItem].fInstallState)
{
pVf = CreateVariableField(WU_KEY_UNINSTALLKEY, (PBYTE)"Yes", 4); // Just to say that uninstall key is present
AddVariableSizeField(&pItem, pVf);
V3_free(pVf);
}
if ( acdmItem[nItem].sPrinterDriverName.length() )
{
pVf = CreateVariableField(WU_CDM_DRIVER_NAME, (PBYTE)(LPTSTR)acdmItem[nItem].sPrinterDriverName.c_str(),
(acdmItem[nItem].sPrinterDriverName.length() + 1) * sizeof(TCHAR));
AddVariableSizeField(&pItem, pVf);
V3_free(pVf);
}
if ( acdmItem[nItem].sArchitecture.length() )
{
pVf = CreateVariableField(WU_CDM_PRINTER_DRIVER_ARCH, (PBYTE)(LPTSTR)acdmItem[nItem].sArchitecture.c_str(),
(acdmItem[nItem].sArchitecture.length() + 1) * sizeof(TCHAR));
AddVariableSizeField(&pItem, pVf);
V3_free(pVf);
}
}
catch(HRESULT hr)
{
if ( pItem )
{
V3_free(pItem);
pItem = 0;
}
}
if (pItem)
m_items[m_iCDMTotalItems++] = pItem;
}
}
//This function installs a driver on Windows NT.
//The active function that is called on NT to install a device driver resides in newdev.dll
//Its prototype is:
//BOOL
//InstallWindowsUpdateDriver(
// HWND hwndParent,
// LPCWSTR HardwareId,
// LPCWSTR InfPathName,
// LPCWSTR DisplayName,
// BOOL Force,
// BOOL Backup,
// PDWORD pReboot
// )
//This API takes a HardwareID. Newdev will cycle through all devices that match this hardware ID
//and install the specified driver on them all.
//It also takes a BOOL value Backup which specifies whether or not to backup the current drivers.
// Note that newdev will only backup the drivers once if we find multiple matches for the HardwareID.
static DWORD InstallNT(
EDriverStatus eds,
LPCTSTR szHwIDs,
LPCTSTR szInfPathName,
LPCTSTR szDisplayName,
PDWORD pReboot
) {
LOG_block("InstallNT");
USES_CONVERSION;
typedef BOOL (*PFN_InstallWindowsUpdateDriver)(HWND hwndParent, LPCWSTR HardwareId, LPCWSTR InfPathName, LPCWSTR DisplayName, BOOL Force, BOOL Backup, PDWORD pReboot);
// Load newdev.dll and get pointer to our function
auto_hlib hlib = LoadLibrary(_T("newdev.dll"));
return_error_if_false(hlib.valid());
PFN_InstallWindowsUpdateDriver pfnInstallWindowsUpdateDriver = (PFN_InstallWindowsUpdateDriver)GetProcAddress(hlib,"InstallWindowsUpdateDriver");
return_error_if_false(pfnInstallWindowsUpdateDriver);
// make sure the hardware ID's are aligned
LPCTSTR szTempHwIDs;
TSTR_ALIGNED_STACK_COPY(&szTempHwIDs, szHwIDs);
szHwIDs = szTempHwIDs;
// walk through Hardware IDs
DWORD dwRebootFinal = 0;
for (LPCTSTR szHwID = szHwIDs; *szHwID; szHwID += lstrlen(szHwID) + 1)
{
tchar_buffer bchInfPathName;
if (edsBackup == eds)
{ // Old INF name is in the registry
return_if_error(GetReinstallString(szHwID, bchInfPathName));
TCHAR* ptr = _tcsrchr((LPCTSTR)bchInfPathName, _T('\\'));
if (ptr)
*ptr = 0; // cut file title
}
else
{
bchInfPathName.resize(lstrlen(szInfPathName) + 1);
return_error_if_false(bchInfPathName.valid());
lstrcpy(bchInfPathName, szInfPathName);
}
BOOL fForce = edsNew != eds;
BOOL fBackup = edsNew == eds;
LOG_out("InstallWindowsUpdateDriver(%s, %s, %s, fForce=%d, fBackup=%d)",
szHwID, (LPCTSTR)bchInfPathName, szDisplayName, fForce, fBackup);
DWORD dwReboot = 0;
BOOL bRc = (pfnInstallWindowsUpdateDriver)(GetActiveWindow(),
T2W((LPTSTR)szHwID), T2W(bchInfPathName), T2W((LPTSTR)szDisplayName), fForce, fBackup, &dwReboot);
DWORD dwError = GetLastError();
LOG_out("InstallWindowsUpdateDriver() returns %d, LastError = %d, need reboot = %d", bRc, dwError, dwReboot);
if ( !bRc )
{
if (NO_ERROR == dwError)
dwError = SPAPI_E_DI_DONT_INSTALL;
return dwError;
}
// cleanup
if ( edsBackup == eds )
{
DeleteReinstallKey(szHwID);
// Delete directory
DeleteNode(bchInfPathName);
// Remove empty directory tree
do
{
//remove *.*
TCHAR* psz = _tcsrchr((LPTSTR)bchInfPathName, _T('\\'));
if (NULL == psz)
break;
*psz = 0;
} while (RemoveDirectory(bchInfPathName));
}
if (dwReboot)
dwRebootFinal = 1;
}
*pReboot = dwRebootFinal;
return NO_ERROR;
}
void CdmInstallDriver(BOOL bWindowsNT, EDriverStatus eds, LPCTSTR szHwIDs, LPCTSTR szInfPathName, LPCTSTR szDisplayName, PDWORD pReboot)
{
DWORD dwError = InstallNT(eds, szHwIDs, szInfPathName, szDisplayName, pReboot);
if (NO_ERROR != dwError )
{
throw HRESULT_FROM_WIN32(dwError);
}
}
//
//We need to create a unique backup directory for this device, so we will
// use the unique Hardware ID to come up with this unique directory.
//Basically I will replace all of the illegal file/registry characters
// \/:*?"<>| with # (for 98) , for NT will only do this with \
//
static void HwID2Key(LPCTSTR szHwID, tchar_buffer& bufKey)
{
static TCHAR szIllegal[] = _T("\\/:*?\"<>|");
if (IsWindowsNT())
szIllegal[1] = 0;
bufKey.resize(ua_lstrlen(szHwID) + 1);
if (!bufKey.valid())
return; // out of memory
// use the macro to copy unligned strings
ua_tcscpy(bufKey, szHwID);
for (TCHAR* pch = bufKey; *pch; pch ++)
{
if (_tcschr(szIllegal, *pch) != NULL)
*pch = _T('#');
}
}
static DWORD RegQueryValueBuf(HKEY hKey, LPCTSTR szValue, tchar_buffer& buf)
{
DWORD dwSize = 0;
DWORD dwError = RegQueryValueEx(hKey, szValue, NULL, NULL, NULL, &dwSize);
if (NO_ERROR != dwError)
return dwError;
buf.resize(dwSize/sizeof(TCHAR));
if (!buf.valid())
return ERROR_OUTOFMEMORY;
return RegQueryValueEx(hKey, szValue, NULL, NULL, (LPBYTE)(LPTSTR)buf, &dwSize);
}
static DWORD OpenReinstallKey(HKEY* phkeyReinstall)
{
return RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reinstall"),
0, KEY_ALL_ACCESS, phkeyReinstall);
}
static DWORD GetReinstallString(LPCTSTR szHwID, tchar_buffer& bchReinstallString)
{
auto_hkey hkeyReinstall;
DWORD dwError = OpenReinstallKey(&hkeyReinstall);
if (NO_ERROR != dwError)
return dwError;
tchar_buffer bufKey;
HwID2Key(szHwID, bufKey);
auto_hkey hkeyHwID;
dwError = RegOpenKeyEx(hkeyReinstall, bufKey, 0, KEY_READ, &hkeyHwID);
if (NO_ERROR != dwError)
return dwError;
return RegQueryValueBuf(hkeyHwID, _T("ReinstallString"), bchReinstallString);
}
static DWORD DeleteReinstallKey(LPCTSTR szHwID)
{
LOG_block("DeleteReinstallKey");
auto_hkey hkeyReinstall;
return_if_error(OpenReinstallKey(&hkeyReinstall));
tchar_buffer bufKey;
HwID2Key(szHwID, bufKey);
return_if_error(RegDeleteKey(hkeyReinstall, bufKey));
return NO_ERROR;
}