Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

450 lines
11 KiB

  1. void DetectActiveSetupInseng(
  2. CWUDownload *pDownload, //Pointer to CWUDLOAD download class to be used to download detection DLLs.
  3. CDiamond *pDiamond, //Pointer to Diamond Expansion class.
  4. CCatalog *pCatalog, //Pointer to catalog that detection CIF is to be created from.
  5. char* szLocalCif //Directory Path Name of local CIF to create.
  6. )
  7. {
  8. PUID puid;
  9. HANDLE hFile;
  10. PINVENTORY_ITEM pItem;
  11. PWU_VARIABLE_FIELD pvTmp;
  12. int i;
  13. int t;
  14. WCHAR szOleStr[64];
  15. char szGuid[64];
  16. char szVersion[64];
  17. char szTmp[MAX_PATH];
  18. char szDllName[128];
  19. PSTR ptr;
  20. int cItemsToDetect = 0;
  21. Varray<PSTR> vDetectDLLs;
  22. int cDetectDLLs = 0;
  23. LOG_block("DetectActiveSetupInseng");
  24. hFile = CreateFile(szLocalCif, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
  25. FILE_ATTRIBUTE_NORMAL, NULL);
  26. if ( hFile == INVALID_HANDLE_VALUE )
  27. throw HRESULT_FROM_WIN32(GetLastError());
  28. //
  29. // For each active setup item that is not pruned write a component entry in the detection cif.
  30. //
  31. for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  32. {
  33. pItem = pCatalog->GetItem(i);
  34. if ( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD ||
  35. (pItem->ps->state == WU_ITEM_STATE_PRUNED))
  36. {
  37. continue;
  38. }
  39. if (!IsValidGuid(&pItem->pf->a.g))
  40. continue;
  41. if (StringFromGUID2(pItem->pf->a.g, szOleStr, sizeof(szOleStr)) == 0)
  42. {
  43. pItem->pf->a.flags |= WU_HIDDEN_ITEM_FLAG;
  44. continue;
  45. }
  46. cItemsToDetect++;
  47. //Download any detection DLLs that need to be copied to the local client.
  48. //Note: These detection DLLs are stored in the WindowsUpdate cache
  49. //directory. This allows the download class to bypass copying these DLL's
  50. //If this detection dll has not alreay been checked for download.
  51. if ( (pvTmp = pItem->pv->Find(WU_KEY_COMPONENT)) )
  52. {
  53. sprintf(szTmp, "[%s]\r\n", pvTmp->pData);
  54. WriteFileString(hFile, szTmp);
  55. }
  56. else
  57. {
  58. //else use the puid as component name
  59. pCatalog->GetItemInfo(i, WU_ITEM_PUID, (PVOID)&puid);
  60. sprintf(szTmp, "[%d]\r\n", puid);
  61. WriteFileString(hFile, szTmp);
  62. }
  63. memset(szGuid, 0, sizeof(szGuid));
  64. WideCharToMultiByte(CP_ACP, 0, szOleStr, -1, szGuid, sizeof(szGuid), NULL, NULL);
  65. sprintf(szTmp, "GUID=%s\r\n", szGuid);
  66. WriteFileString(hFile, szTmp);
  67. VersionToString(&pItem->pf->a.version, szVersion);
  68. sprintf(szTmp, "Version=%s\r\n", szVersion);
  69. WriteFileString(hFile, szTmp);
  70. //
  71. // detection dll variable fields
  72. //
  73. szDllName[0] = '\0';
  74. if (pItem->pv->Find(WU_DETECT_DLL_REG_KEY_EXISTS))
  75. {
  76. //
  77. // WUDETECT.DLL,RegKeyExists special case
  78. //
  79. WriteFileString(hFile, "DetectVersion=wudetect.dll,RegKeyExists\r\n");
  80. strcpy(szDllName, "wudetect.bin");
  81. }
  82. if ((pvTmp = pItem->pv->Find(WU_DETECT_DLL_GENERIC)))
  83. {
  84. //
  85. // generic detection DLL including WUDETECT.DLL,RegKeyVersion case
  86. //
  87. sprintf(szTmp, "DetectVersion=%s\r\n", pvTmp->pData);
  88. WriteFileString(hFile, szTmp);
  89. //
  90. // parse out detection dll name from DetectVersion= value
  91. //
  92. if ((ptr = (PSTR)_memccpy(szDllName, (char *)pvTmp->pData, '.', sizeof(szDllName))))
  93. *(ptr - 1) = 0;
  94. strcat(szDllName, ".bin");
  95. //
  96. // check for RegKeyVersion special case
  97. //
  98. if (_stricmp(szDllName, "wudetect.bin") == 0)
  99. {
  100. if (stristr((const char *)pvTmp->pData, "RegKeyVersion") != NULL)
  101. {
  102. WriteFileString(hFile, "_DetRegVersion=Version\r\n");
  103. }
  104. }
  105. }
  106. if (szDllName[0] != '\0')
  107. {
  108. //
  109. // check and see if this detection DLL has not been checked for downloaded already.
  110. //
  111. for (t = 0; t < cDetectDLLs; t++)
  112. {
  113. if (_stricmp(vDetectDLLs[t], szDllName) == 0)
  114. break;
  115. }
  116. //
  117. // add it to the detection DLL array.
  118. //
  119. if (t == cDetectDLLs)
  120. {
  121. vDetectDLLs[cDetectDLLs] = (PSTR)V3_malloc(strlen(szDllName)+1);
  122. strcpy(vDetectDLLs[cDetectDLLs], szDllName);
  123. cDetectDLLs++;
  124. }
  125. }
  126. //
  127. // other variable length fields
  128. //
  129. if ((pvTmp = pItem->pv->Find(WU_DETREGKEY)))
  130. {
  131. sprintf(szTmp, "_DetRegKey=%s\r\n", pvTmp->pData);
  132. WriteFileString(hFile, szTmp);
  133. }
  134. if (pItem->pv->Find(WU_DETREGVALUE_INSTALLED_SZ1))
  135. WriteFileString(hFile, "_DetRegValue=Installed,SZ,1\r\n");
  136. if ((pvTmp = pItem->pv->Find(WU_DETREGVALUE_INSTALLED_GENERIC)))
  137. {
  138. sprintf(szTmp, "_DetRegValue=%s\r\n", pvTmp->pData);
  139. WriteFileString(hFile, szTmp);
  140. }
  141. if ((pvTmp = pItem->pv->Find(WU_KEY_STRING)))
  142. {
  143. WriteFileString(hFile, (char *)pvTmp->pData);
  144. WriteFileString(hFile, (char *)"\r\n");
  145. }
  146. if ((pvTmp = pItem->pv->Find(WU_KEY_UNINSTALLKEY)))
  147. {
  148. sprintf(szTmp, "UninstallKey=%s\r\n", pvTmp->pData);
  149. WriteFileString(hFile, szTmp);
  150. }
  151. //
  152. //If no locale specified then use * since this is the active setup default.
  153. //Note: This may need to change to a loop if multiple active setup detection
  154. //locales end up needing to be specified for a single inventory item.
  155. //
  156. if ( !(pvTmp = pItem->pv->Find(WU_DET_CIF_LOCALE)) )
  157. sprintf(szTmp, "Locale=\"*\"\r\n");
  158. else
  159. sprintf(szTmp, "Locale=\"%s\"\r\n", pvTmp->pData);
  160. WriteFileString(hFile, szTmp);
  161. }
  162. CloseHandle(hFile);
  163. //
  164. // Download all unique detection DLLs
  165. //
  166. for (i = 0; i < cDetectDLLs; i++)
  167. {
  168. try
  169. {
  170. char szPath[MAX_PATH];
  171. //
  172. // construct full path for the detection dll
  173. //
  174. sprintf(szPath, "Detect/%d/%s", pCatalog->GetPlatform(), vDetectDLLs[i]);
  175. DownloadDLL(pDiamond, pDownload, vDetectDLLs[i], szPath);
  176. }
  177. catch(HRESULT hr)
  178. {
  179. //
  180. // There is a posibility that the DLL may be in memory and DownloadDLL call will throw
  181. //
  182. TRACE("Could not replace detection DLL %s", vDetectDLLs[i]);
  183. }
  184. V3_free(vDetectDLLs[i]);
  185. }
  186. //
  187. // do active setup detection
  188. //
  189. if (cItemsToDetect > 0)
  190. {
  191. InsengDetection(pCatalog, szLocalCif);
  192. }
  193. LOG_out("%d items were detected", cItemsToDetect);
  194. }
  195. //This function performs all active setup detection for active setup items in
  196. //the specified catalog. Note: The MakeDetectionCIF API needs to be called
  197. //before this method can perform any detection.
  198. void InsengDetection(
  199. CCatalog *pCatalog, //Catalog to perform active setup detection on.
  200. char *szLocalCif //CIF created with the MakeDetectionCIF API.
  201. )
  202. {
  203. MSG msg;
  204. int i;
  205. GUID g;
  206. DWORD dwComponentStatus;
  207. HRESULT hr;
  208. ICifFile *picif;
  209. ICifComponent *pcomp;
  210. IInstallEngine *pInsEngTemp;
  211. IInstallEngine2 *pInsEng;
  212. IEnumCifComponents *penum;
  213. PINVENTORY_ITEM pItem;
  214. int iTotalItems;
  215. WCHAR szOle[64];
  216. char szPUID[32];
  217. char szLocalDir[MAX_PATH];
  218. char *ptr;
  219. char szGUID[64];
  220. PUID puid;
  221. BOOL bMatch;
  222. picif = NULL;
  223. penum = NULL;
  224. pInsEng = NULL;
  225. pInsEngTemp = NULL;
  226. pcomp = NULL;
  227. LOG_block("InsengDetection");
  228. try
  229. {
  230. //perform active setup detection
  231. hr = CoCreateInstance(CLSID_InstallEngine, NULL, CLSCTX_INPROC_SERVER, IID_IInstallEngine, (void **)&pInsEngTemp);
  232. if ( FAILED(hr) )
  233. throw hr;
  234. hr = pInsEngTemp->QueryInterface(IID_IInstallEngine2, (void **)&pInsEng);
  235. if ( FAILED(hr) )
  236. throw hr;
  237. //The local directory is the CIF file directory with out
  238. //the CIF file extension. So we find the last slash in
  239. //the CIF path string and temporarly NULL terminate it.
  240. //This allows us to extract the local detection
  241. //directory and set active setup inseng.dll engine to
  242. //use it without have to wait for ActiveSetup to perform
  243. //a grovel of each local hard drive in order to find out
  244. //the amount of free space each drive has.
  245. ptr = strrchr(szLocalCif, '\\');
  246. if ( ptr )
  247. {
  248. *ptr = 0;
  249. strcpy(szLocalDir, szLocalCif);
  250. *ptr = '\\';
  251. }
  252. //Everything we do in V3 detection is with a local CIF.
  253. hr = pInsEng->SetLocalCif(szLocalCif);
  254. if ( FAILED(hr) )
  255. throw hr;
  256. //Set downoad directory don't let active setup determine
  257. //this as it takes it forever.
  258. hr = pInsEng->SetDownloadDir(szLocalDir);
  259. if ( FAILED(hr) )
  260. throw hr;
  261. //Now we get the CIF component interface enum each
  262. //component and tell active setup to detect it.
  263. hr = pInsEng->GetICifFile(&picif);
  264. if ( FAILED(hr) )
  265. throw hr;
  266. hr = picif->EnumComponents(&penum, 0, NULL);
  267. if ( FAILED(hr) )
  268. throw hr;
  269. iTotalItems = pCatalog->GetHeader()->totalItems;
  270. while (SUCCEEDED(penum->Next(&pcomp)))
  271. {
  272. pcomp->GetID(szPUID, sizeof(szPUID));
  273. puid = atoi(szPUID);
  274. if (puid == 0)
  275. {
  276. pcomp->GetGUID(szGUID, sizeof(szGUID));
  277. if (!MultiByteToWideChar(CP_ACP, 0, szGUID, sizeof(szGUID), szOle, sizeof(szOle)))
  278. continue;
  279. if (CLSIDFromString(szOle, (CLSID *)&g) == CO_E_CLASSSTRING) //illformed GUID
  280. continue;
  281. }
  282. dwComponentStatus = pcomp->IsComponentInstalled();
  283. //Find this guid in inventory array if we don't find the the item
  284. //then there is nothing we can do since the component that active
  285. //setup thinks it detected does not exit.
  286. for(i = 0; i < iTotalItems; i++)
  287. {
  288. pItem = pCatalog->GetItem(i);
  289. if ( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD ||
  290. (pItem->ps->state == WU_ITEM_STATE_PRUNED))
  291. {
  292. continue;
  293. }
  294. if (puid != 0)
  295. bMatch = (pItem->pf->a.puid == puid);
  296. else
  297. bMatch = (IsEqualGUID(pItem->pf->a.g, g));
  298. if (bMatch)
  299. {
  300. //If the component was found remap active setups
  301. //status codes to our own so that the pruning
  302. //logic knows what to do with them.
  303. switch( dwComponentStatus )
  304. {
  305. case ICI_NOTINSTALLED: //0 = item not installed(INSTALL)
  306. pItem->ps->state = WU_ITEM_STATE_INSTALL;
  307. break;
  308. case ICI_INSTALLED: //1 = this item is curretly installed
  309. pItem->ps->state = WU_ITEM_STATE_CURRENT;
  310. break;
  311. case ICI_NEWVERSIONAVAILABLE: //2 Items is installed but newer available
  312. pItem->ps->state = WU_ITEM_STATE_UPDATE;
  313. break;
  314. case ICI_UNKNOWN: //3 cannot be determined
  315. case ICI_OLDVERSIONAVAILABLE: //4 Why would anyone want to install the older version?
  316. case ICI_NOTINITIALIZED: //0xffffffff
  317. default:
  318. pItem->ps->bHidden = TRUE;
  319. pItem->ps->state = WU_ITEM_STATE_PRUNED;
  320. break;
  321. }
  322. break;
  323. }
  324. while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  325. {
  326. TranslateMessage(&msg);
  327. DispatchMessage(&msg);
  328. }
  329. }
  330. //Perform active setup detection for each component.
  331. }
  332. }
  333. catch(HRESULT hr)
  334. {
  335. //If an error occurs then release all our stuff and rethrow the error.
  336. if ( penum )
  337. penum->Release();
  338. if ( picif )
  339. picif->Release();
  340. if ( pInsEngTemp )
  341. pInsEngTemp->Release();
  342. if ( pInsEng )
  343. pInsEng->Release();
  344. throw hr;
  345. }
  346. if ( penum )
  347. penum->Release();
  348. if ( picif )
  349. picif->Release();
  350. if ( pInsEngTemp )
  351. pInsEngTemp->Release();
  352. if ( pInsEng )
  353. pInsEng->Release();
  354. return;
  355. }
  356. //This function forms a simple string write it is used with the MakeDetectionCIF
  357. //function to write CIF entries into the created detection CIF.
  358. void WriteFileString(
  359. HANDLE hFile,
  360. PSTR szString
  361. )
  362. {
  363. ULONG bytes;
  364. if ( !WriteFile(hFile, (LPCVOID)szString, strlen(szString), (unsigned long *)&bytes, NULL) )
  365. {
  366. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  367. CloseHandle(hFile);
  368. throw hr;
  369. }
  370. }