windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wuv3is/insengdet.txt
2020-09-26 16:20:57 +08:00

451 lines
11 KiB
Plaintext

void DetectActiveSetupInseng(
CWUDownload *pDownload, //Pointer to CWUDLOAD download class to be used to download detection DLLs.
CDiamond *pDiamond, //Pointer to Diamond Expansion class.
CCatalog *pCatalog, //Pointer to catalog that detection CIF is to be created from.
char* szLocalCif //Directory Path Name of local CIF to create.
)
{
PUID puid;
HANDLE hFile;
PINVENTORY_ITEM pItem;
PWU_VARIABLE_FIELD pvTmp;
int i;
int t;
WCHAR szOleStr[64];
char szGuid[64];
char szVersion[64];
char szTmp[MAX_PATH];
char szDllName[128];
PSTR ptr;
int cItemsToDetect = 0;
Varray<PSTR> vDetectDLLs;
int cDetectDLLs = 0;
LOG_block("DetectActiveSetupInseng");
hFile = CreateFile(szLocalCif, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
throw HRESULT_FROM_WIN32(GetLastError());
//
// For each active setup item that is not pruned write a component entry in the detection cif.
//
for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
pItem = pCatalog->GetItem(i);
if ( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD ||
(pItem->ps->state == WU_ITEM_STATE_PRUNED))
{
continue;
}
if (!IsValidGuid(&pItem->pf->a.g))
continue;
if (StringFromGUID2(pItem->pf->a.g, szOleStr, sizeof(szOleStr)) == 0)
{
pItem->pf->a.flags |= WU_HIDDEN_ITEM_FLAG;
continue;
}
cItemsToDetect++;
//Download any detection DLLs that need to be copied to the local client.
//Note: These detection DLLs are stored in the WindowsUpdate cache
//directory. This allows the download class to bypass copying these DLL's
//If this detection dll has not alreay been checked for download.
if ( (pvTmp = pItem->pv->Find(WU_KEY_COMPONENT)) )
{
sprintf(szTmp, "[%s]\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
}
else
{
//else use the puid as component name
pCatalog->GetItemInfo(i, WU_ITEM_PUID, (PVOID)&puid);
sprintf(szTmp, "[%d]\r\n", puid);
WriteFileString(hFile, szTmp);
}
memset(szGuid, 0, sizeof(szGuid));
WideCharToMultiByte(CP_ACP, 0, szOleStr, -1, szGuid, sizeof(szGuid), NULL, NULL);
sprintf(szTmp, "GUID=%s\r\n", szGuid);
WriteFileString(hFile, szTmp);
VersionToString(&pItem->pf->a.version, szVersion);
sprintf(szTmp, "Version=%s\r\n", szVersion);
WriteFileString(hFile, szTmp);
//
// detection dll variable fields
//
szDllName[0] = '\0';
if (pItem->pv->Find(WU_DETECT_DLL_REG_KEY_EXISTS))
{
//
// WUDETECT.DLL,RegKeyExists special case
//
WriteFileString(hFile, "DetectVersion=wudetect.dll,RegKeyExists\r\n");
strcpy(szDllName, "wudetect.bin");
}
if ((pvTmp = pItem->pv->Find(WU_DETECT_DLL_GENERIC)))
{
//
// generic detection DLL including WUDETECT.DLL,RegKeyVersion case
//
sprintf(szTmp, "DetectVersion=%s\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
//
// parse out detection dll name from DetectVersion= value
//
if ((ptr = (PSTR)_memccpy(szDllName, (char *)pvTmp->pData, '.', sizeof(szDllName))))
*(ptr - 1) = 0;
strcat(szDllName, ".bin");
//
// check for RegKeyVersion special case
//
if (_stricmp(szDllName, "wudetect.bin") == 0)
{
if (stristr((const char *)pvTmp->pData, "RegKeyVersion") != NULL)
{
WriteFileString(hFile, "_DetRegVersion=Version\r\n");
}
}
}
if (szDllName[0] != '\0')
{
//
// check and see if this detection DLL has not been checked for downloaded already.
//
for (t = 0; t < cDetectDLLs; t++)
{
if (_stricmp(vDetectDLLs[t], szDllName) == 0)
break;
}
//
// add it to the detection DLL array.
//
if (t == cDetectDLLs)
{
vDetectDLLs[cDetectDLLs] = (PSTR)V3_malloc(strlen(szDllName)+1);
strcpy(vDetectDLLs[cDetectDLLs], szDllName);
cDetectDLLs++;
}
}
//
// other variable length fields
//
if ((pvTmp = pItem->pv->Find(WU_DETREGKEY)))
{
sprintf(szTmp, "_DetRegKey=%s\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
}
if (pItem->pv->Find(WU_DETREGVALUE_INSTALLED_SZ1))
WriteFileString(hFile, "_DetRegValue=Installed,SZ,1\r\n");
if ((pvTmp = pItem->pv->Find(WU_DETREGVALUE_INSTALLED_GENERIC)))
{
sprintf(szTmp, "_DetRegValue=%s\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
}
if ((pvTmp = pItem->pv->Find(WU_KEY_STRING)))
{
WriteFileString(hFile, (char *)pvTmp->pData);
WriteFileString(hFile, (char *)"\r\n");
}
if ((pvTmp = pItem->pv->Find(WU_KEY_UNINSTALLKEY)))
{
sprintf(szTmp, "UninstallKey=%s\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
}
//
//If no locale specified then use * since this is the active setup default.
//Note: This may need to change to a loop if multiple active setup detection
//locales end up needing to be specified for a single inventory item.
//
if ( !(pvTmp = pItem->pv->Find(WU_DET_CIF_LOCALE)) )
sprintf(szTmp, "Locale=\"*\"\r\n");
else
sprintf(szTmp, "Locale=\"%s\"\r\n", pvTmp->pData);
WriteFileString(hFile, szTmp);
}
CloseHandle(hFile);
//
// Download all unique detection DLLs
//
for (i = 0; i < cDetectDLLs; i++)
{
try
{
char szPath[MAX_PATH];
//
// construct full path for the detection dll
//
sprintf(szPath, "Detect/%d/%s", pCatalog->GetPlatform(), vDetectDLLs[i]);
DownloadDLL(pDiamond, pDownload, vDetectDLLs[i], szPath);
}
catch(HRESULT hr)
{
//
// There is a posibility that the DLL may be in memory and DownloadDLL call will throw
//
TRACE("Could not replace detection DLL %s", vDetectDLLs[i]);
}
V3_free(vDetectDLLs[i]);
}
//
// do active setup detection
//
if (cItemsToDetect > 0)
{
InsengDetection(pCatalog, szLocalCif);
}
LOG_out("%d items were detected", cItemsToDetect);
}
//This function performs all active setup detection for active setup items in
//the specified catalog. Note: The MakeDetectionCIF API needs to be called
//before this method can perform any detection.
void InsengDetection(
CCatalog *pCatalog, //Catalog to perform active setup detection on.
char *szLocalCif //CIF created with the MakeDetectionCIF API.
)
{
MSG msg;
int i;
GUID g;
DWORD dwComponentStatus;
HRESULT hr;
ICifFile *picif;
ICifComponent *pcomp;
IInstallEngine *pInsEngTemp;
IInstallEngine2 *pInsEng;
IEnumCifComponents *penum;
PINVENTORY_ITEM pItem;
int iTotalItems;
WCHAR szOle[64];
char szPUID[32];
char szLocalDir[MAX_PATH];
char *ptr;
char szGUID[64];
PUID puid;
BOOL bMatch;
picif = NULL;
penum = NULL;
pInsEng = NULL;
pInsEngTemp = NULL;
pcomp = NULL;
LOG_block("InsengDetection");
try
{
//perform active setup detection
hr = CoCreateInstance(CLSID_InstallEngine, NULL, CLSCTX_INPROC_SERVER, IID_IInstallEngine, (void **)&pInsEngTemp);
if ( FAILED(hr) )
throw hr;
hr = pInsEngTemp->QueryInterface(IID_IInstallEngine2, (void **)&pInsEng);
if ( FAILED(hr) )
throw hr;
//The local directory is the CIF file directory with out
//the CIF file extension. So we find the last slash in
//the CIF path string and temporarly NULL terminate it.
//This allows us to extract the local detection
//directory and set active setup inseng.dll engine to
//use it without have to wait for ActiveSetup to perform
//a grovel of each local hard drive in order to find out
//the amount of free space each drive has.
ptr = strrchr(szLocalCif, '\\');
if ( ptr )
{
*ptr = 0;
strcpy(szLocalDir, szLocalCif);
*ptr = '\\';
}
//Everything we do in V3 detection is with a local CIF.
hr = pInsEng->SetLocalCif(szLocalCif);
if ( FAILED(hr) )
throw hr;
//Set downoad directory don't let active setup determine
//this as it takes it forever.
hr = pInsEng->SetDownloadDir(szLocalDir);
if ( FAILED(hr) )
throw hr;
//Now we get the CIF component interface enum each
//component and tell active setup to detect it.
hr = pInsEng->GetICifFile(&picif);
if ( FAILED(hr) )
throw hr;
hr = picif->EnumComponents(&penum, 0, NULL);
if ( FAILED(hr) )
throw hr;
iTotalItems = pCatalog->GetHeader()->totalItems;
while (SUCCEEDED(penum->Next(&pcomp)))
{
pcomp->GetID(szPUID, sizeof(szPUID));
puid = atoi(szPUID);
if (puid == 0)
{
pcomp->GetGUID(szGUID, sizeof(szGUID));
if (!MultiByteToWideChar(CP_ACP, 0, szGUID, sizeof(szGUID), szOle, sizeof(szOle)))
continue;
if (CLSIDFromString(szOle, (CLSID *)&g) == CO_E_CLASSSTRING) //illformed GUID
continue;
}
dwComponentStatus = pcomp->IsComponentInstalled();
//Find this guid in inventory array if we don't find the the item
//then there is nothing we can do since the component that active
//setup thinks it detected does not exit.
for(i = 0; i < iTotalItems; i++)
{
pItem = pCatalog->GetItem(i);
if ( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD ||
(pItem->ps->state == WU_ITEM_STATE_PRUNED))
{
continue;
}
if (puid != 0)
bMatch = (pItem->pf->a.puid == puid);
else
bMatch = (IsEqualGUID(pItem->pf->a.g, g));
if (bMatch)
{
//If the component was found remap active setups
//status codes to our own so that the pruning
//logic knows what to do with them.
switch( dwComponentStatus )
{
case ICI_NOTINSTALLED: //0 = item not installed(INSTALL)
pItem->ps->state = WU_ITEM_STATE_INSTALL;
break;
case ICI_INSTALLED: //1 = this item is curretly installed
pItem->ps->state = WU_ITEM_STATE_CURRENT;
break;
case ICI_NEWVERSIONAVAILABLE: //2 Items is installed but newer available
pItem->ps->state = WU_ITEM_STATE_UPDATE;
break;
case ICI_UNKNOWN: //3 cannot be determined
case ICI_OLDVERSIONAVAILABLE: //4 Why would anyone want to install the older version?
case ICI_NOTINITIALIZED: //0xffffffff
default:
pItem->ps->bHidden = TRUE;
pItem->ps->state = WU_ITEM_STATE_PRUNED;
break;
}
break;
}
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//Perform active setup detection for each component.
}
}
catch(HRESULT hr)
{
//If an error occurs then release all our stuff and rethrow the error.
if ( penum )
penum->Release();
if ( picif )
picif->Release();
if ( pInsEngTemp )
pInsEngTemp->Release();
if ( pInsEng )
pInsEng->Release();
throw hr;
}
if ( penum )
penum->Release();
if ( picif )
picif->Release();
if ( pInsEngTemp )
pInsEngTemp->Release();
if ( pInsEng )
pInsEng->Release();
return;
}
//This function forms a simple string write it is used with the MakeDetectionCIF
//function to write CIF entries into the created detection CIF.
void WriteFileString(
HANDLE hFile,
PSTR szString
)
{
ULONG bytes;
if ( !WriteFile(hFile, (LPCVOID)szString, strlen(szString), (unsigned long *)&bytes, NULL) )
{
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
throw hr;
}
}