diff options
Diffstat (limited to 'src/samples/Dtf/Inventory/components.cs')
-rw-r--r-- | src/samples/Dtf/Inventory/components.cs | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/src/samples/Dtf/Inventory/components.cs b/src/samples/Dtf/Inventory/components.cs new file mode 100644 index 00000000..c5147084 --- /dev/null +++ b/src/samples/Dtf/Inventory/components.cs | |||
@@ -0,0 +1,626 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | using System; | ||
4 | using System.IO; | ||
5 | using System.Data; | ||
6 | using System.Text; | ||
7 | using System.Collections; | ||
8 | using System.Collections.Generic; | ||
9 | using System.Globalization; | ||
10 | using System.Windows.Forms; | ||
11 | using Microsoft.Win32; | ||
12 | using WixToolset.Dtf.WindowsInstaller; | ||
13 | using View = WixToolset.Dtf.WindowsInstaller.View; | ||
14 | |||
15 | namespace WixToolset.Dtf.Samples.Inventory | ||
16 | { | ||
17 | /// <summary> | ||
18 | /// Provides inventory data about components of products installed on the system. | ||
19 | /// </summary> | ||
20 | public class ComponentsInventory : IInventoryDataProvider | ||
21 | { | ||
22 | private static object syncRoot = new object(); | ||
23 | |||
24 | public ComponentsInventory() | ||
25 | { | ||
26 | } | ||
27 | |||
28 | public string Description | ||
29 | { | ||
30 | get { return "Components of installed products"; } | ||
31 | } | ||
32 | |||
33 | private Hashtable componentProductsMap; | ||
34 | |||
35 | public string[] GetNodes(InventoryDataLoadStatusCallback statusCallback) | ||
36 | { | ||
37 | ArrayList nodes = new ArrayList(); | ||
38 | componentProductsMap = new Hashtable(); | ||
39 | foreach(ProductInstallation product in ProductInstallation.AllProducts) | ||
40 | { | ||
41 | string productName = MsiUtils.GetProductName(product.ProductCode); | ||
42 | statusCallback(nodes.Count, String.Format(@"Products\{0}", productName)); | ||
43 | |||
44 | try | ||
45 | { | ||
46 | IntPtr hWnd = IntPtr.Zero; | ||
47 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
48 | lock(syncRoot) // Only one Installer session can be active at a time | ||
49 | { | ||
50 | using (Session session = Installer.OpenProduct(product.ProductCode)) | ||
51 | { | ||
52 | statusCallback(nodes.Count, String.Format(@"Products\{0}\Features", productName)); | ||
53 | IList<string> features = session.Database.ExecuteStringQuery("SELECT `Feature` FROM `Feature`"); | ||
54 | string[] featuresArray = new string[features.Count]; | ||
55 | features.CopyTo(featuresArray, 0); | ||
56 | Array.Sort(featuresArray, 0, featuresArray.Length, StringComparer.OrdinalIgnoreCase); | ||
57 | foreach (string feature in featuresArray) | ||
58 | { | ||
59 | nodes.Add(String.Format(@"Products\{0}\Features\{1}", productName, feature)); | ||
60 | } | ||
61 | statusCallback(nodes.Count, String.Format(@"Products\{0}\Components", productName)); | ||
62 | nodes.Add(String.Format(@"Products\{0}\Components", productName)); | ||
63 | IList<string> components = session.Database.ExecuteStringQuery("SELECT `ComponentId` FROM `Component`"); | ||
64 | for (int i = 0; i < components.Count; i++) | ||
65 | { | ||
66 | string component = components[i]; | ||
67 | if (component.Length > 0) | ||
68 | { | ||
69 | nodes.Add(String.Format(@"Products\{0}\Components\{1}", productName, component)); | ||
70 | ArrayList sharingProducts = (ArrayList) componentProductsMap[component]; | ||
71 | if (sharingProducts == null) | ||
72 | { | ||
73 | sharingProducts = new ArrayList(); | ||
74 | componentProductsMap[component] = sharingProducts; | ||
75 | } | ||
76 | sharingProducts.Add(product.ProductCode); | ||
77 | } | ||
78 | if (i % 100 == 0) statusCallback(nodes.Count, null); | ||
79 | } | ||
80 | nodes.Add(String.Format(@"Products\{0}\Files", productName)); | ||
81 | nodes.Add(String.Format(@"Products\{0}\Registry", productName)); | ||
82 | statusCallback(nodes.Count, String.Empty); | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | catch(InstallerException) { } | ||
87 | } | ||
88 | statusCallback(nodes.Count, @"Products\...\Components\...\Sharing"); | ||
89 | foreach (DictionaryEntry componentProducts in componentProductsMap) | ||
90 | { | ||
91 | string component = (string) componentProducts.Key; | ||
92 | ArrayList products = (ArrayList) componentProducts.Value; | ||
93 | if(products.Count > 1) | ||
94 | { | ||
95 | foreach(string productCode in products) | ||
96 | { | ||
97 | nodes.Add(String.Format(@"Products\{0}\Components\{1}\Sharing", MsiUtils.GetProductName(productCode), component)); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | statusCallback(nodes.Count, String.Empty); | ||
102 | return (string[]) nodes.ToArray(typeof(string)); | ||
103 | } | ||
104 | |||
105 | public bool IsNodeSearchable(string searchRoot, string searchNode) | ||
106 | { | ||
107 | string[] rootPath = searchRoot.Split('\\'); | ||
108 | string[] nodePath = searchNode.Split('\\'); | ||
109 | if(rootPath.Length < 3 && nodePath.Length >= 3 && nodePath[0] == "Products" && nodePath[2] == "Components") | ||
110 | { | ||
111 | // When searching an entire product, don't search the "Components" subtree -- | ||
112 | // it just has duplicate data from the Files and Registry table. And if you | ||
113 | // really want to know about the component, it's only a click away from | ||
114 | // those other tables. | ||
115 | return false; | ||
116 | } | ||
117 | return true; | ||
118 | } | ||
119 | |||
120 | public DataView GetData(string nodePath) | ||
121 | { | ||
122 | string[] path = nodePath.Split('\\'); | ||
123 | |||
124 | if(path.Length == 4 && path[0] == "Products" && path[2] == "Features") | ||
125 | { | ||
126 | return GetFeatureComponentsData(MsiUtils.GetProductCode(path[1]), path[3]); | ||
127 | } | ||
128 | else if(path.Length == 3 && path[0] == "Products" && path[2] == "Components") | ||
129 | { | ||
130 | return GetProductComponentsData(MsiUtils.GetProductCode(path[1])); | ||
131 | } | ||
132 | else if(path.Length == 4 && path[0] == "Products" && path[2] == "Components") | ||
133 | { | ||
134 | return GetComponentData(MsiUtils.GetProductCode(path[1]), path[3]); | ||
135 | } | ||
136 | else if(path.Length == 5 && path[0] == "Products" && path[2] == "Components" && path[4] == "Sharing") | ||
137 | { | ||
138 | return GetComponentProductsData(path[3]); | ||
139 | } | ||
140 | else if(path.Length == 3 && path[0] == "Products" && path[2] == "Files") | ||
141 | { | ||
142 | return GetProductFilesData(MsiUtils.GetProductCode(path[1])); | ||
143 | } | ||
144 | else if(path.Length == 3 && path[0] == "Products" && path[2] == "Registry") | ||
145 | { | ||
146 | return GetProductRegistryData(MsiUtils.GetProductCode(path[1])); | ||
147 | } | ||
148 | return null; | ||
149 | } | ||
150 | |||
151 | public DataView GetComponentData(string productCode, string componentCode) | ||
152 | { | ||
153 | DataTable table = new DataTable("ProductComponentItems"); | ||
154 | table.Locale = CultureInfo.InvariantCulture; | ||
155 | table.Columns.Add("ProductComponentItemsIsKey", typeof(bool)); | ||
156 | table.Columns.Add("ProductComponentItemsKey", typeof(string)); | ||
157 | table.Columns.Add("ProductComponentItemsPath", typeof(string)); | ||
158 | table.Columns.Add("ProductComponentItemsExists", typeof(bool)); | ||
159 | table.Columns.Add("ProductComponentItemsDbVersion", typeof(string)); | ||
160 | table.Columns.Add("ProductComponentItemsInstalledVersion", typeof(string)); | ||
161 | table.Columns.Add("ProductComponentItemsInstalledMatch", typeof(bool)); | ||
162 | try | ||
163 | { | ||
164 | IntPtr hWnd = IntPtr.Zero; | ||
165 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
166 | lock(syncRoot) // Only one Installer session can be active at a time | ||
167 | { | ||
168 | using(Session session = Installer.OpenProduct(productCode)) | ||
169 | { | ||
170 | session.DoAction("CostInitialize"); | ||
171 | session.DoAction("FileCost"); | ||
172 | session.DoAction("CostFinalize"); | ||
173 | |||
174 | foreach(object[] row in this.GetComponentFilesRows(productCode, componentCode, session, false)) | ||
175 | { | ||
176 | table.Rows.Add(row); | ||
177 | } | ||
178 | foreach(object[] row in this.GetComponentRegistryRows(productCode, componentCode, session, false)) | ||
179 | { | ||
180 | table.Rows.Add(row); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | return new DataView(table, "", "ProductComponentItemsPath ASC", DataViewRowState.CurrentRows); | ||
185 | } | ||
186 | catch(InstallerException) { } | ||
187 | return null; | ||
188 | } | ||
189 | |||
190 | private object[][] GetComponentFilesRows(string productCode, string componentCode, Session session, bool includeComponent) | ||
191 | { | ||
192 | ArrayList rows = new ArrayList(); | ||
193 | string componentPath = new ComponentInstallation(componentCode, productCode).Path; | ||
194 | |||
195 | string componentKey = (string) session.Database.ExecuteScalar( | ||
196 | "SELECT `Component` FROM `Component` WHERE `ComponentId` = '{0}'", componentCode); | ||
197 | if(componentKey == null) return null; | ||
198 | int attributes = Convert.ToInt32(session.Database.ExecuteScalar( | ||
199 | "SELECT `Attributes` FROM `Component` WHERE `Component` = '{0}'", componentKey)); | ||
200 | bool registryKeyPath = (attributes & (int) ComponentAttributes.RegistryKeyPath) != 0; | ||
201 | if(!registryKeyPath && componentPath.Length > 0) componentPath = Path.GetDirectoryName(componentPath); | ||
202 | string keyPath = (string) session.Database.ExecuteScalar( | ||
203 | "SELECT `KeyPath` FROM `Component` WHERE `Component` = '{0}'", componentKey); | ||
204 | |||
205 | using (View view = session.Database.OpenView("SELECT `File`, `FileName`, `Version`, `Language`, " + | ||
206 | "`Attributes` FROM `File` WHERE `Component_` = '{0}'", componentKey)) | ||
207 | { | ||
208 | view.Execute(); | ||
209 | |||
210 | foreach (Record rec in view) using (rec) | ||
211 | { | ||
212 | string fileKey = (string) rec["File"]; | ||
213 | bool isKey = !registryKeyPath && keyPath == fileKey; | ||
214 | |||
215 | string dbVersion = (string) rec["Version"]; | ||
216 | bool versionedFile = dbVersion.Length != 0; | ||
217 | if(versionedFile) | ||
218 | { | ||
219 | string language = (string) rec["Language"]; | ||
220 | if(language.Length > 0) | ||
221 | { | ||
222 | dbVersion = dbVersion + " (" + language + ")"; | ||
223 | } | ||
224 | } | ||
225 | else if(session.Database.Tables.Contains("MsiFileHash")) | ||
226 | { | ||
227 | IList<int> hash = session.Database.ExecuteIntegerQuery("SELECT `HashPart1`, `HashPart2`, " + | ||
228 | "`HashPart3`, `HashPart4` FROM `MsiFileHash` WHERE `File_` = '{0}'", fileKey); | ||
229 | if(hash != null && hash.Count == 4) | ||
230 | { | ||
231 | dbVersion = this.GetFileHashString(hash); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | string filePath = GetLongFileName((string) rec["FileName"]); | ||
236 | bool exists = false; | ||
237 | bool installedMatch = false; | ||
238 | string installedVersion = ""; | ||
239 | if(!registryKeyPath && componentPath.Length > 0) | ||
240 | { | ||
241 | filePath = Path.Combine(componentPath, filePath); | ||
242 | |||
243 | if(File.Exists(filePath)) | ||
244 | { | ||
245 | exists = true; | ||
246 | if(versionedFile) | ||
247 | { | ||
248 | installedVersion = Installer.GetFileVersion(filePath); | ||
249 | string language = Installer.GetFileLanguage(filePath); | ||
250 | if(language.Length > 0) | ||
251 | { | ||
252 | installedVersion = installedVersion + " (" + language + ")"; | ||
253 | } | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | int[] hash = new int[4]; | ||
258 | Installer.GetFileHash(filePath, hash); | ||
259 | installedVersion = this.GetFileHashString(hash); | ||
260 | } | ||
261 | installedMatch = installedVersion == dbVersion; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | object[] row; | ||
266 | if(includeComponent) row = new object[] { isKey, fileKey, filePath, exists, dbVersion, installedVersion, installedMatch, componentCode }; | ||
267 | else row = new object[] { isKey, fileKey, filePath, exists, dbVersion, installedVersion, installedMatch }; | ||
268 | rows.Add(row); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | return (object[][]) rows.ToArray(typeof(object[])); | ||
273 | } | ||
274 | |||
275 | private string GetLongFileName(string fileName) | ||
276 | { | ||
277 | string[] fileNames = fileName.Split('|'); | ||
278 | return fileNames.Length == 1? fileNames[0] : fileNames[1]; | ||
279 | } | ||
280 | |||
281 | private string GetFileHashString(IList<int> hash) | ||
282 | { | ||
283 | return String.Format("{0:X8}{1:X8}{2:X8}{3:X8}", (uint) hash[0], (uint) hash[1], (uint) hash[2], (uint) hash[3]); | ||
284 | } | ||
285 | |||
286 | private object[][] GetComponentRegistryRows(string productCode, string componentCode, Session session, bool includeComponent) | ||
287 | { | ||
288 | ArrayList rows = new ArrayList(); | ||
289 | string componentPath = new ComponentInstallation(componentCode, productCode).Path; | ||
290 | |||
291 | string componentKey = (string) session.Database.ExecuteScalar( | ||
292 | "SELECT `Component` FROM `Component` WHERE `ComponentId` = '{0}'", componentCode); | ||
293 | if(componentKey == null) return null; | ||
294 | int attributes = Convert.ToInt32(session.Database.ExecuteScalar( | ||
295 | "SELECT `Attributes` FROM `Component` WHERE `Component` = '{0}'", componentKey)); | ||
296 | bool registryKeyPath = (attributes & (int) ComponentAttributes.RegistryKeyPath) != 0; | ||
297 | if(!registryKeyPath && componentPath.Length > 0) componentPath = Path.GetDirectoryName(componentPath); | ||
298 | string keyPath = (string) session.Database.ExecuteScalar( | ||
299 | "SELECT `KeyPath` FROM `Component` WHERE `Component` = '{0}'", componentKey); | ||
300 | |||
301 | using (View view = session.Database.OpenView("SELECT `Registry`, `Root`, `Key`, `Name`, " + | ||
302 | "`Value` FROM `Registry` WHERE `Component_` = '{0}'", componentKey)) | ||
303 | { | ||
304 | view.Execute(); | ||
305 | |||
306 | foreach (Record rec in view) using (rec) | ||
307 | { | ||
308 | string regName = (string) rec["Name"]; | ||
309 | if(regName == "-") continue; // Don't list deleted keys | ||
310 | |||
311 | string regTableKey = (string) rec["Registry"]; | ||
312 | bool isKey = registryKeyPath && keyPath == regTableKey; | ||
313 | string regPath = this.GetRegistryPath(session, (RegistryRoot) Convert.ToInt32(rec["Root"]), | ||
314 | (string) rec["Key"], (string) rec["Name"]); | ||
315 | |||
316 | string dbValue; | ||
317 | using(Record formatRec = new Record(0)) | ||
318 | { | ||
319 | formatRec[0] = rec["Value"]; | ||
320 | dbValue = session.FormatRecord(formatRec); | ||
321 | } | ||
322 | |||
323 | string installedValue = this.GetRegistryValue(regPath); | ||
324 | bool exists = installedValue != null; | ||
325 | if(!exists) installedValue = ""; | ||
326 | bool match = installedValue == dbValue; | ||
327 | |||
328 | object[] row; | ||
329 | if(includeComponent) row = new object[] { isKey, regTableKey, regPath, exists, dbValue, installedValue, match, componentCode }; | ||
330 | else row = new object[] { isKey, regTableKey, regPath, exists, dbValue, installedValue, match }; | ||
331 | rows.Add(row); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | return (object[][]) rows.ToArray(typeof(object[])); | ||
336 | } | ||
337 | |||
338 | private string GetRegistryPath(Session session, RegistryRoot root, string key, string name) | ||
339 | { | ||
340 | bool allUsers = session.EvaluateCondition("ALLUSERS = 1", true); | ||
341 | string rootName = "????"; | ||
342 | switch(root) | ||
343 | { | ||
344 | case RegistryRoot.LocalMachine : rootName = "HKLM"; break; | ||
345 | case RegistryRoot.CurrentUser : rootName = "HKCU"; break; | ||
346 | case RegistryRoot.Users : rootName = "HKU"; break; | ||
347 | case RegistryRoot.UserOrMachine: rootName = (allUsers ? "HKLM" : "HKCU"); break; | ||
348 | case RegistryRoot.ClassesRoot : rootName = (allUsers ? @"HKLM\Software\Classes" : @"HKCU\Software\Classes"); break; | ||
349 | // TODO: Technically, RegistryRoot.ClassesRoot should be under HKLM on NT4. | ||
350 | } | ||
351 | if(name.Length == 0) name = "(Default)"; | ||
352 | if(name == "+" || name == "*") name = ""; | ||
353 | else name = " : " + name; | ||
354 | using(Record formatRec = new Record(0)) | ||
355 | { | ||
356 | formatRec[0] = String.Format(@"{0}\{1}{2}", rootName, key, name); | ||
357 | return session.FormatRecord(formatRec); | ||
358 | } | ||
359 | } | ||
360 | |||
361 | private string GetRegistryValue(string regPath) | ||
362 | { | ||
363 | string valueName = null; | ||
364 | int iColon = regPath.IndexOf(" : ", StringComparison.Ordinal) + 1; | ||
365 | if(iColon > 0) | ||
366 | { | ||
367 | valueName = regPath.Substring(iColon + 2); | ||
368 | regPath = regPath.Substring(0, iColon - 1); | ||
369 | } | ||
370 | if(valueName == "(Default)") valueName = ""; | ||
371 | |||
372 | RegistryKey root; | ||
373 | if(regPath.StartsWith(@"HKLM\", StringComparison.Ordinal)) | ||
374 | { | ||
375 | root = Registry.LocalMachine; | ||
376 | regPath = regPath.Substring(5); | ||
377 | } | ||
378 | else if(regPath.StartsWith(@"HKCU\", StringComparison.Ordinal)) | ||
379 | { | ||
380 | root = Registry.CurrentUser; | ||
381 | regPath = regPath.Substring(5); | ||
382 | } | ||
383 | else if(regPath.StartsWith(@"HKU\", StringComparison.Ordinal)) | ||
384 | { | ||
385 | root = Registry.Users; | ||
386 | regPath = regPath.Substring(4); | ||
387 | } | ||
388 | else return null; | ||
389 | |||
390 | using(RegistryKey regKey = root.OpenSubKey(regPath)) | ||
391 | { | ||
392 | if(regKey != null) | ||
393 | { | ||
394 | if(valueName == null) | ||
395 | { | ||
396 | // Just checking for the existence of the key. | ||
397 | return ""; | ||
398 | } | ||
399 | object value = regKey.GetValue(valueName); | ||
400 | if(value is string[]) | ||
401 | { | ||
402 | value = String.Join("[~]", (string[]) value); | ||
403 | } | ||
404 | else if(value is int) | ||
405 | { | ||
406 | value = "#" + value.ToString(); | ||
407 | } | ||
408 | else if(value is byte[]) | ||
409 | { | ||
410 | byte[] valueBytes = (byte[]) value; | ||
411 | StringBuilder byteString = new StringBuilder("#x"); | ||
412 | for(int i = 0; i < valueBytes.Length; i++) | ||
413 | { | ||
414 | byteString.Append(valueBytes[i].ToString("x2")); | ||
415 | } | ||
416 | value = byteString.ToString(); | ||
417 | } | ||
418 | return (value != null ? value.ToString() : null); | ||
419 | } | ||
420 | } | ||
421 | return null; | ||
422 | } | ||
423 | |||
424 | public DataView GetProductFilesData(string productCode) | ||
425 | { | ||
426 | DataTable table = new DataTable("ProductFiles"); | ||
427 | table.Locale = CultureInfo.InvariantCulture; | ||
428 | table.Columns.Add("ProductFilesIsKey", typeof(bool)); | ||
429 | table.Columns.Add("ProductFilesKey", typeof(string)); | ||
430 | table.Columns.Add("ProductFilesPath", typeof(string)); | ||
431 | table.Columns.Add("ProductFilesExists", typeof(bool)); | ||
432 | table.Columns.Add("ProductFilesDbVersion", typeof(string)); | ||
433 | table.Columns.Add("ProductFilesInstalledVersion", typeof(string)); | ||
434 | table.Columns.Add("ProductFilesInstalledMatch", typeof(bool)); | ||
435 | table.Columns.Add("ProductFilesComponentID", typeof(string)); | ||
436 | try | ||
437 | { | ||
438 | IntPtr hWnd = IntPtr.Zero; | ||
439 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
440 | lock(syncRoot) // Only one Installer session can be active at a time | ||
441 | { | ||
442 | using(Session session = Installer.OpenProduct(productCode)) | ||
443 | { | ||
444 | session.DoAction("CostInitialize"); | ||
445 | session.DoAction("FileCost"); | ||
446 | session.DoAction("CostFinalize"); | ||
447 | |||
448 | foreach(string componentCode in session.Database.ExecuteStringQuery("SELECT `ComponentId` FROM `Component`")) | ||
449 | { | ||
450 | foreach(object[] row in this.GetComponentFilesRows(productCode, componentCode, session, true)) | ||
451 | { | ||
452 | table.Rows.Add(row); | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | return new DataView(table, "", "ProductFilesPath ASC", DataViewRowState.CurrentRows); | ||
458 | } | ||
459 | catch(InstallerException) { } | ||
460 | return null; | ||
461 | } | ||
462 | |||
463 | public DataView GetProductRegistryData(string productCode) | ||
464 | { | ||
465 | DataTable table = new DataTable("ProductRegistry"); | ||
466 | table.Locale = CultureInfo.InvariantCulture; | ||
467 | table.Columns.Add("ProductRegistryIsKey", typeof(bool)); | ||
468 | table.Columns.Add("ProductRegistryKey", typeof(string)); | ||
469 | table.Columns.Add("ProductRegistryPath", typeof(string)); | ||
470 | table.Columns.Add("ProductRegistryExists", typeof(bool)); | ||
471 | table.Columns.Add("ProductRegistryDbVersion", typeof(string)); | ||
472 | table.Columns.Add("ProductRegistryInstalledVersion", typeof(string)); | ||
473 | table.Columns.Add("ProductRegistryInstalledMatch", typeof(bool)); | ||
474 | table.Columns.Add("ProductRegistryComponentID", typeof(string)); | ||
475 | try | ||
476 | { | ||
477 | IntPtr hWnd = IntPtr.Zero; | ||
478 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
479 | lock(syncRoot) // Only one Installer session can be active at a time | ||
480 | { | ||
481 | using(Session session = Installer.OpenProduct(productCode)) | ||
482 | { | ||
483 | session.DoAction("CostInitialize"); | ||
484 | session.DoAction("FileCost"); | ||
485 | session.DoAction("CostFinalize"); | ||
486 | |||
487 | foreach(string componentCode in session.Database.ExecuteStringQuery("SELECT `ComponentId` FROM `Component`")) | ||
488 | { | ||
489 | foreach(object[] row in this.GetComponentRegistryRows(productCode, componentCode, session, true)) | ||
490 | { | ||
491 | table.Rows.Add(row); | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | return new DataView(table, "", "ProductRegistryPath ASC", DataViewRowState.CurrentRows); | ||
497 | } | ||
498 | catch(InstallerException) { } | ||
499 | return null; | ||
500 | } | ||
501 | |||
502 | public DataView GetComponentProductsData(string componentCode) | ||
503 | { | ||
504 | DataTable table = new DataTable("ComponentProducts"); | ||
505 | table.Locale = CultureInfo.InvariantCulture; | ||
506 | table.Columns.Add("ComponentProductsProductName", typeof(string)); | ||
507 | table.Columns.Add("ComponentProductsProductCode", typeof(string)); | ||
508 | table.Columns.Add("ComponentProductsComponentPath", typeof(string)); | ||
509 | |||
510 | if(this.componentProductsMap != null) | ||
511 | { | ||
512 | ArrayList componentProducts = (ArrayList) this.componentProductsMap[componentCode]; | ||
513 | foreach(string productCode in componentProducts) | ||
514 | { | ||
515 | string productName = MsiUtils.GetProductName(productCode); | ||
516 | string componentPath = new ComponentInstallation(componentCode, productCode).Path; | ||
517 | table.Rows.Add(new object[] { productName, productCode, componentPath }); | ||
518 | } | ||
519 | return new DataView(table, "", "ComponentProductsProductName ASC", DataViewRowState.CurrentRows); | ||
520 | } | ||
521 | return null; | ||
522 | } | ||
523 | |||
524 | public DataView GetProductComponentsData(string productCode) | ||
525 | { | ||
526 | DataTable table = new DataTable("ProductComponents"); | ||
527 | table.Locale = CultureInfo.InvariantCulture; | ||
528 | table.Columns.Add("ProductComponentsComponentName", typeof(string)); | ||
529 | table.Columns.Add("ProductComponentsComponentID", typeof(string)); | ||
530 | table.Columns.Add("ProductComponentsInstallState", typeof(string)); | ||
531 | |||
532 | try | ||
533 | { | ||
534 | IntPtr hWnd = IntPtr.Zero; | ||
535 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
536 | lock(syncRoot) // Only one Installer session can be active at a time | ||
537 | { | ||
538 | using(Session session = Installer.OpenProduct(productCode)) | ||
539 | { | ||
540 | session.DoAction("CostInitialize"); | ||
541 | session.DoAction("FileCost"); | ||
542 | session.DoAction("CostFinalize"); | ||
543 | |||
544 | IList<string> componentsAndIds = session.Database.ExecuteStringQuery( | ||
545 | "SELECT `Component`, `ComponentId` FROM `Component`"); | ||
546 | |||
547 | for (int i = 0; i < componentsAndIds.Count; i += 2) | ||
548 | { | ||
549 | if(componentsAndIds[i+1] == "Temporary Id") continue; | ||
550 | InstallState compState = session.Components[componentsAndIds[i]].CurrentState; | ||
551 | table.Rows.Add(new object[] { componentsAndIds[i], componentsAndIds[i+1], | ||
552 | (compState == InstallState.Advertised ? "Advertised" : compState.ToString())}); | ||
553 | } | ||
554 | } | ||
555 | } | ||
556 | return new DataView(table, "", "ProductComponentsComponentName ASC", DataViewRowState.CurrentRows); | ||
557 | } | ||
558 | catch(InstallerException) { } | ||
559 | return null; | ||
560 | } | ||
561 | |||
562 | public DataView GetFeatureComponentsData(string productCode, string feature) | ||
563 | { | ||
564 | DataTable table = new DataTable("ProductFeatureComponents"); | ||
565 | table.Locale = CultureInfo.InvariantCulture; | ||
566 | table.Columns.Add("ProductFeatureComponentsComponentName", typeof(string)); | ||
567 | table.Columns.Add("ProductFeatureComponentsComponentID", typeof(string)); | ||
568 | |||
569 | try | ||
570 | { | ||
571 | IntPtr hWnd = IntPtr.Zero; | ||
572 | Installer.SetInternalUI(InstallUIOptions.Silent, ref hWnd); | ||
573 | lock(syncRoot) // Only one Installer session can be active at a time | ||
574 | { | ||
575 | using(Session session = Installer.OpenProduct(productCode)) | ||
576 | { | ||
577 | IList<string> componentsAndIds = session.Database.ExecuteStringQuery( | ||
578 | "SELECT `FeatureComponents`.`Component_`, " + | ||
579 | "`Component`.`ComponentId` FROM `FeatureComponents`, `Component` " + | ||
580 | "WHERE `FeatureComponents`.`Component_` = `Component`.`Component` " + | ||
581 | "AND `FeatureComponents`.`Feature_` = '{0}'", feature); | ||
582 | for (int i = 0; i < componentsAndIds.Count; i += 2) | ||
583 | { | ||
584 | table.Rows.Add(new object[] { componentsAndIds[i], componentsAndIds[i+1] }); | ||
585 | } | ||
586 | } | ||
587 | } | ||
588 | return new DataView(table, "", "ProductFeatureComponentsComponentName ASC", DataViewRowState.CurrentRows); | ||
589 | } | ||
590 | catch(InstallerException) { } | ||
591 | return null; | ||
592 | } | ||
593 | |||
594 | public string GetLink(string nodePath, DataRow row) | ||
595 | { | ||
596 | string[] path = nodePath.Split('\\'); | ||
597 | |||
598 | if(path.Length == 3 && path[0] == "Products" && path[2] == "Components") | ||
599 | { | ||
600 | string component = (string) row["ProductComponentsComponentID"]; | ||
601 | return String.Format(@"Products\{0}\Components\{1}", path[1], component); | ||
602 | } | ||
603 | else if(path.Length == 4 && path[0] == "Products" && path[2] == "Features") | ||
604 | { | ||
605 | string component = (string) row["ProductFeatureComponentsComponentID"]; | ||
606 | return String.Format(@"Products\{0}\Components\{1}", path[1], component); | ||
607 | } | ||
608 | else if(path.Length == 3 && path[0] == "Products" && path[2] == "Files") | ||
609 | { | ||
610 | string component = (string) row["ProductFilesComponentID"]; | ||
611 | return String.Format(@"Products\{0}\Components\{1}", path[1], component); | ||
612 | } | ||
613 | else if(path.Length == 3 && path[0] == "Products" && path[2] == "Registry") | ||
614 | { | ||
615 | string component = (string) row["ProductRegistryComponentID"]; | ||
616 | return String.Format(@"Products\{0}\Components\{1}", path[1], component); | ||
617 | } | ||
618 | else if(path.Length == 5 && path[0] == "Products" && path[2] == "Components" && path[4] == "Sharing") | ||
619 | { | ||
620 | string product = (string) row["ComponentProductsProductCode"]; | ||
621 | return String.Format(@"Products\{0}\Components\{1}", MsiUtils.GetProductName(product), path[3]); | ||
622 | } | ||
623 | return null; | ||
624 | } | ||
625 | } | ||
626 | } | ||