diff options
Diffstat (limited to '')
-rw-r--r-- | src/dtf/WixToolset.Dtf.WindowsInstaller/Installer.cs | 890 |
1 files changed, 890 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/Installer.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/Installer.cs new file mode 100644 index 00000000..8df0aed9 --- /dev/null +++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/Installer.cs | |||
@@ -0,0 +1,890 @@ | |||
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 | namespace WixToolset.Dtf.WindowsInstaller | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Text; | ||
8 | using System.Resources; | ||
9 | using System.Reflection; | ||
10 | using System.Collections.Generic; | ||
11 | using System.Globalization; | ||
12 | using System.Runtime.InteropServices; | ||
13 | using System.Diagnostics.CodeAnalysis; | ||
14 | |||
15 | /// <summary> | ||
16 | /// Receives an exception from | ||
17 | /// <see cref="Installer.DetermineApplicablePatches(string,string[],InapplicablePatchHandler,string,UserContexts)"/> | ||
18 | /// indicating the reason a particular patch is not applicable to a product. | ||
19 | /// </summary> | ||
20 | /// <param name="patch">MSP file path, XML file path, or XML blob that was passed to | ||
21 | /// <see cref="Installer.DetermineApplicablePatches(string,string[],InapplicablePatchHandler,string,UserContexts)"/></param> | ||
22 | /// <param name="exception">exception indicating the reason the patch is not applicable</param> | ||
23 | /// <remarks><p> | ||
24 | /// If <paramref name="exception"/> is an <see cref="InstallerException"/> or subclass, then | ||
25 | /// its <see cref="InstallerException.ErrorCode"/> and <see cref="InstallerException.Message"/> | ||
26 | /// properties will indicate a more specific reason the patch was not applicable. | ||
27 | /// </p><p> | ||
28 | /// The <paramref name="exception"/> could also be a FileNotFoundException if the | ||
29 | /// patch string was a file path. | ||
30 | /// </p></remarks> | ||
31 | public delegate void InapplicablePatchHandler(string patch, Exception exception); | ||
32 | |||
33 | /// <summary> | ||
34 | /// Provides static methods for installing and configuring products and patches. | ||
35 | /// </summary> | ||
36 | public static partial class Installer | ||
37 | { | ||
38 | private static bool rebootRequired; | ||
39 | private static bool rebootInitiated; | ||
40 | private static ResourceManager errorResources; | ||
41 | |||
42 | /// <summary> | ||
43 | /// Indicates whether a system reboot is required after running an installation or configuration operation. | ||
44 | /// </summary> | ||
45 | public static bool RebootRequired | ||
46 | { | ||
47 | get | ||
48 | { | ||
49 | return Installer.rebootRequired; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /// <summary> | ||
54 | /// Indicates whether a system reboot has been initiated after running an installation or configuration operation. | ||
55 | /// </summary> | ||
56 | public static bool RebootInitiated | ||
57 | { | ||
58 | get | ||
59 | { | ||
60 | return Installer.rebootInitiated; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Enables the installer's internal user interface. Then this user interface is used | ||
66 | /// for all subsequent calls to user-interface-generating installer functions in this process. | ||
67 | /// </summary> | ||
68 | /// <param name="uiOptions">Specifies the level of complexity of the user interface</param> | ||
69 | /// <param name="windowHandle">Handle to a window, which becomes the owner of any user interface created. | ||
70 | /// A pointer to the previous owner of the user interface is returned.</param> | ||
71 | /// <returns>The previous user interface level</returns> | ||
72 | /// <remarks><p> | ||
73 | /// Win32 MSI API: | ||
74 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetinternalui.asp">MsiSetInternalUI</a> | ||
75 | /// </p></remarks> | ||
76 | [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] | ||
77 | public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions, ref IntPtr windowHandle) | ||
78 | { | ||
79 | return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, ref windowHandle); | ||
80 | } | ||
81 | |||
82 | /// <summary> | ||
83 | /// Enables the installer's internal user interface. Then this user interface is used | ||
84 | /// for all subsequent calls to user-interface-generating installer functions in this process. | ||
85 | /// The owner of the user interface does not change. | ||
86 | /// </summary> | ||
87 | /// <param name="uiOptions">Specifies the level of complexity of the user interface</param> | ||
88 | /// <returns>The previous user interface level</returns> | ||
89 | /// <remarks><p> | ||
90 | /// Win32 MSI API: | ||
91 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetinternalui.asp">MsiSetInternalUI</a> | ||
92 | /// </p></remarks> | ||
93 | public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions) | ||
94 | { | ||
95 | return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, IntPtr.Zero); | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Enables logging of the selected message type for all subsequent install sessions in | ||
100 | /// the current process space. | ||
101 | /// </summary> | ||
102 | /// <param name="logModes">One or more mode flags specifying the type of messages to log</param> | ||
103 | /// <param name="logFile">Full path to the log file. A null path disables logging, | ||
104 | /// in which case the logModes paraneter is ignored.</param> | ||
105 | /// <exception cref="ArgumentException">an invalid log mode was specified</exception> | ||
106 | /// <remarks>This method takes effect on any new installation processes. Calling this | ||
107 | /// method from within a custom action will not start logging for that installation.</remarks> | ||
108 | public static void EnableLog(InstallLogModes logModes, string logFile) | ||
109 | { | ||
110 | Installer.EnableLog(logModes, logFile, false, true); | ||
111 | } | ||
112 | |||
113 | /// <summary> | ||
114 | /// Enables logging of the selected message type for all subsequent install sessions in | ||
115 | /// the current process space. | ||
116 | /// </summary> | ||
117 | /// <param name="logModes">One or more mode flags specifying the type of messages to log</param> | ||
118 | /// <param name="logFile">Full path to the log file. A null path disables logging, | ||
119 | /// in which case the logModes paraneter is ignored.</param> | ||
120 | /// <param name="append">If true, the log lines will be appended to any existing file content. | ||
121 | /// If false, the log file will be truncated if it exists. The default is false.</param> | ||
122 | /// <param name="flushEveryLine">If true, the log will be flushed after every line. | ||
123 | /// If false, the log will be flushed every 20 lines. The default is true.</param> | ||
124 | /// <exception cref="ArgumentException">an invalid log mode was specified</exception> | ||
125 | /// <remarks><p> | ||
126 | /// This method takes effect on any new installation processes. Calling this | ||
127 | /// method from within a custom action will not start logging for that installation. | ||
128 | /// </p><p> | ||
129 | /// Win32 MSI API: | ||
130 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienablelog.asp">MsiEnableLog</a> | ||
131 | /// </p></remarks> | ||
132 | public static void EnableLog(InstallLogModes logModes, string logFile, bool append, bool flushEveryLine) | ||
133 | { | ||
134 | uint ret = NativeMethods.MsiEnableLog((uint) logModes, logFile, (append ? (uint) 1 : 0) + (flushEveryLine ? (uint) 2 : 0)); | ||
135 | if (ret != 0 && ret != (uint) NativeMethods.Error.FILE_INVALID) | ||
136 | { | ||
137 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /// <summary> | ||
142 | /// increments the usage count for a particular feature and returns the installation state for | ||
143 | /// that feature. This method should be used to indicate an application's intent to use a feature. | ||
144 | /// </summary> | ||
145 | /// <param name="productCode">The product code of the product.</param> | ||
146 | /// <param name="feature">The feature to be used.</param> | ||
147 | /// <param name="installMode">Must have the value <see cref="InstallMode.NoDetection"/>.</param> | ||
148 | /// <returns>The installed state of the feature.</returns> | ||
149 | /// <remarks><p> | ||
150 | /// The UseFeature method should only be used on features known to be published. The application | ||
151 | /// should determine the status of the feature by calling either the FeatureState method or | ||
152 | /// Features method. | ||
153 | /// </p><p> | ||
154 | /// Win32 MSI APIs: | ||
155 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiusefeature.asp">MsiUseFeature</a>, | ||
156 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiusefeatureex.asp">MsiUseFeatureEx</a> | ||
157 | /// </p></remarks> | ||
158 | public static InstallState UseFeature(string productCode, string feature, InstallMode installMode) | ||
159 | { | ||
160 | int installState = NativeMethods.MsiUseFeatureEx(productCode, feature, unchecked ((uint) installMode), 0); | ||
161 | return (InstallState) installState; | ||
162 | } | ||
163 | |||
164 | /// <summary> | ||
165 | /// Opens an installer package for use with functions that access the product database and install engine, | ||
166 | /// returning an Session object. | ||
167 | /// </summary> | ||
168 | /// <param name="packagePath">Path to the package</param> | ||
169 | /// <param name="ignoreMachineState">Specifies whether or not the create a Session object that ignores the | ||
170 | /// computer state and that is incapable of changing the current computer state. A value of false yields | ||
171 | /// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current | ||
172 | /// machine state.</param> | ||
173 | /// <returns>A Session object allowing access to the product database and install engine</returns> | ||
174 | /// <exception cref="InstallerException">The product could not be opened</exception> | ||
175 | /// <exception cref="InstallerException">The installer configuration data is corrupt</exception> | ||
176 | /// <remarks><p> | ||
177 | /// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a | ||
178 | /// custom action because the active installation is the only session allowed. | ||
179 | /// </p><p> | ||
180 | /// A "safe" Session object ignores the current computer state when opening the package and prevents | ||
181 | /// changes to the current computer state. | ||
182 | /// </p><p> | ||
183 | /// The Session object should be <see cref="InstallerHandle.Close"/>d after use. | ||
184 | /// It is best that the handle be closed manually as soon as it is no longer | ||
185 | /// needed, as leaving lots of unused handles open can degrade performance. | ||
186 | /// </p><p> | ||
187 | /// Win32 MSI APIs: | ||
188 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackage.asp">MsiOpenPackage</a>, | ||
189 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackageex.asp">MsiOpenPackageEx</a> | ||
190 | /// </p></remarks> | ||
191 | public static Session OpenPackage(string packagePath, bool ignoreMachineState) | ||
192 | { | ||
193 | int sessionHandle; | ||
194 | uint ret = NativeMethods.MsiOpenPackageEx(packagePath, ignoreMachineState ? (uint) 1 : 0, out sessionHandle); | ||
195 | if (ret != 0) | ||
196 | { | ||
197 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
198 | } | ||
199 | return new Session((IntPtr) sessionHandle, true); | ||
200 | } | ||
201 | |||
202 | /// <summary> | ||
203 | /// Opens an installer package for use with functions that access the product database and install engine, | ||
204 | /// returning an Session object. | ||
205 | /// </summary> | ||
206 | /// <param name="database">Database used to create the session</param> | ||
207 | /// <param name="ignoreMachineState">Specifies whether or not the create a Session object that ignores the | ||
208 | /// computer state and that is incapable of changing the current computer state. A value of false yields | ||
209 | /// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current | ||
210 | /// machine state.</param> | ||
211 | /// <returns>A Session object allowing access to the product database and install engine</returns> | ||
212 | /// <exception cref="InstallerException">The product could not be opened</exception> | ||
213 | /// <exception cref="InstallerException">The installer configuration data is corrupt</exception> | ||
214 | /// <remarks><p> | ||
215 | /// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a | ||
216 | /// custom action because the active installation is the only session allowed. | ||
217 | /// </p><p> | ||
218 | /// A "safe" Session object ignores the current computer state when opening the package and prevents | ||
219 | /// changes to the current computer state. | ||
220 | /// </p><p> | ||
221 | /// The Session object should be <see cref="InstallerHandle.Close"/>d after use. | ||
222 | /// It is best that the handle be closed manually as soon as it is no longer | ||
223 | /// needed, as leaving lots of unused handles open can degrade performance. | ||
224 | /// </p><p> | ||
225 | /// Win32 MSI APIs: | ||
226 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackage.asp">MsiOpenPackage</a>, | ||
227 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackageex.asp">MsiOpenPackageEx</a> | ||
228 | /// </p></remarks> | ||
229 | [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] | ||
230 | public static Session OpenPackage(Database database, bool ignoreMachineState) | ||
231 | { | ||
232 | if (database == null) | ||
233 | { | ||
234 | throw new ArgumentNullException("database"); | ||
235 | } | ||
236 | |||
237 | return Installer.OpenPackage( | ||
238 | String.Format(CultureInfo.InvariantCulture, "#{0}", database.Handle), | ||
239 | ignoreMachineState); | ||
240 | } | ||
241 | |||
242 | /// <summary> | ||
243 | /// Opens an installer package for an installed product using the product code. | ||
244 | /// </summary> | ||
245 | /// <param name="productCode">Product code of the installed product</param> | ||
246 | /// <returns>A Session object allowing access to the product database and install engine, | ||
247 | /// or null if the specified product is not installed.</returns> | ||
248 | /// <exception cref="ArgumentException">An unknown product was requested</exception> | ||
249 | /// <exception cref="InstallerException">The product could not be opened</exception> | ||
250 | /// <exception cref="InstallerException">The installer configuration data is corrupt</exception> | ||
251 | /// <remarks><p> | ||
252 | /// Note that only one Session object can be opened by a single process. OpenProduct cannot be | ||
253 | /// used in a custom action because the active installation is the only session allowed. | ||
254 | /// </p><p> | ||
255 | /// The Session object should be <see cref="InstallerHandle.Close"/>d after use. | ||
256 | /// It is best that the handle be closed manually as soon as it is no longer | ||
257 | /// needed, as leaving lots of unused handles open can degrade performance. | ||
258 | /// </p><p> | ||
259 | /// Win32 MSI API: | ||
260 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenproduct.asp">MsiOpenProduct</a> | ||
261 | /// </p></remarks> | ||
262 | public static Session OpenProduct(string productCode) | ||
263 | { | ||
264 | int sessionHandle; | ||
265 | uint ret = NativeMethods.MsiOpenProduct(productCode, out sessionHandle); | ||
266 | if (ret != 0) | ||
267 | { | ||
268 | if (ret == (uint) NativeMethods.Error.UNKNOWN_PRODUCT) | ||
269 | { | ||
270 | return null; | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
275 | } | ||
276 | } | ||
277 | return new Session((IntPtr) sessionHandle, true); | ||
278 | } | ||
279 | |||
280 | /// <summary> | ||
281 | /// Gets the full component path, performing any necessary installation. This method prompts for source if | ||
282 | /// necessary and increments the usage count for the feature. | ||
283 | /// </summary> | ||
284 | /// <param name="product">Product code for the product that contains the feature with the necessary component</param> | ||
285 | /// <param name="feature">Feature ID of the feature with the necessary component</param> | ||
286 | /// <param name="component">Component code of the necessary component</param> | ||
287 | /// <param name="installMode">Installation mode; this can also include bits from <see cref="ReinstallModes"/></param> | ||
288 | /// <returns>Path to the component</returns> | ||
289 | /// <remarks><p> | ||
290 | /// Win32 MSI API: | ||
291 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovidecomponent.asp">MsiProvideComponent</a> | ||
292 | /// </p></remarks> | ||
293 | public static string ProvideComponent(string product, string feature, string component, InstallMode installMode) | ||
294 | { | ||
295 | StringBuilder pathBuf = new StringBuilder(512); | ||
296 | uint pathBufSize = (uint) pathBuf.Capacity; | ||
297 | uint ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize); | ||
298 | if (ret == (uint) NativeMethods.Error.MORE_DATA) | ||
299 | { | ||
300 | pathBuf.Capacity = (int) ++pathBufSize; | ||
301 | ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize); | ||
302 | } | ||
303 | |||
304 | if (ret != 0) | ||
305 | { | ||
306 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
307 | } | ||
308 | return pathBuf.ToString(); | ||
309 | } | ||
310 | |||
311 | /// <summary> | ||
312 | /// Gets the full component path for a qualified component that is published by a product and | ||
313 | /// performs any necessary installation. This method prompts for source if necessary and increments | ||
314 | /// the usage count for the feature. | ||
315 | /// </summary> | ||
316 | /// <param name="component">Specifies the component ID for the requested component. This may not be the | ||
317 | /// GUID for the component itself but rather a server that provides the correct functionality, as in the | ||
318 | /// ComponentId column of the PublishComponent table.</param> | ||
319 | /// <param name="qualifier">Specifies a qualifier into a list of advertising components (from PublishComponent Table).</param> | ||
320 | /// <param name="installMode">Installation mode; this can also include bits from <see cref="ReinstallModes"/></param> | ||
321 | /// <param name="product">Optional; specifies the product to match that has published the qualified component.</param> | ||
322 | /// <returns>Path to the component</returns> | ||
323 | /// <remarks><p> | ||
324 | /// Win32 MSI APIs: | ||
325 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovidequalifiedcomponent.asp">MsiProvideQualifiedComponent</a> | ||
326 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovidequalifiedcomponentex.asp">MsiProvideQualifiedComponentEx</a> | ||
327 | /// </p></remarks> | ||
328 | public static string ProvideQualifiedComponent(string component, string qualifier, InstallMode installMode, string product) | ||
329 | { | ||
330 | StringBuilder pathBuf = new StringBuilder(512); | ||
331 | uint pathBufSize = (uint) pathBuf.Capacity; | ||
332 | uint ret = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize); | ||
333 | if (ret == (uint) NativeMethods.Error.MORE_DATA) | ||
334 | { | ||
335 | pathBuf.Capacity = (int) ++pathBufSize; | ||
336 | ret = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize); | ||
337 | } | ||
338 | |||
339 | if (ret != 0) | ||
340 | { | ||
341 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
342 | } | ||
343 | return pathBuf.ToString(); | ||
344 | } | ||
345 | |||
346 | /// <summary> | ||
347 | /// Gets the full path to a Windows Installer component containing an assembly. This method prompts for a source and | ||
348 | /// increments the usage count for the feature. | ||
349 | /// </summary> | ||
350 | /// <param name="assemblyName">Assembly name</param> | ||
351 | /// <param name="appContext">Set to null for global assemblies. For private assemblies, set to the full path of the | ||
352 | /// application configuration file (.cfg file) or executable file (.exe) of the application to which the assembly | ||
353 | /// has been made private.</param> | ||
354 | /// <param name="installMode">Installation mode; this can also include bits from <see cref="ReinstallModes"/></param> | ||
355 | /// <param name="isWin32Assembly">True if this is a Win32 assembly, false if it is a .NET assembly</param> | ||
356 | /// <returns>Path to the assembly</returns> | ||
357 | /// <remarks><p> | ||
358 | /// Win32 MSI API: | ||
359 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovideassembly.asp">MsiProvideAssembly</a> | ||
360 | /// </p></remarks> | ||
361 | public static string ProvideAssembly(string assemblyName, string appContext, InstallMode installMode, bool isWin32Assembly) | ||
362 | { | ||
363 | StringBuilder pathBuf = new StringBuilder(512); | ||
364 | uint pathBufSize = (uint) pathBuf.Capacity; | ||
365 | uint ret = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint) installMode), (isWin32Assembly ? (uint) 1 : 0), pathBuf, ref pathBufSize); | ||
366 | if (ret == (uint) NativeMethods.Error.MORE_DATA) | ||
367 | { | ||
368 | pathBuf.Capacity = (int) ++pathBufSize; | ||
369 | ret = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint) installMode), (isWin32Assembly ? (uint) 1 : 0), pathBuf, ref pathBufSize); | ||
370 | } | ||
371 | |||
372 | if (ret != 0) | ||
373 | { | ||
374 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
375 | } | ||
376 | return pathBuf.ToString(); | ||
377 | } | ||
378 | |||
379 | /// <summary> | ||
380 | /// Installs files that are unexpectedly missing. | ||
381 | /// </summary> | ||
382 | /// <param name="product">Product code for the product that owns the component to be installed</param> | ||
383 | /// <param name="component">Component to be installed</param> | ||
384 | /// <param name="installState">Specifies the way the component should be installed.</param> | ||
385 | /// <exception cref="InstallCanceledException">the user exited the installation</exception> | ||
386 | /// <remarks><p> | ||
387 | /// Win32 MSI API: | ||
388 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiinstallmissingcomponent.asp">MsiInstallMissingComponent</a> | ||
389 | /// </p></remarks> | ||
390 | public static void InstallMissingComponent(string product, string component, InstallState installState) | ||
391 | { | ||
392 | uint ret = NativeMethods.MsiInstallMissingComponent(product, component, (int) installState); | ||
393 | if (ret != 0) | ||
394 | { | ||
395 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /// <summary> | ||
400 | /// Installs files that are unexpectedly missing. | ||
401 | /// </summary> | ||
402 | /// <param name="product">Product code for the product that owns the file to be installed</param> | ||
403 | /// <param name="file">File to be installed</param> | ||
404 | /// <exception cref="InstallCanceledException">the user exited the installation</exception> | ||
405 | /// <remarks><p> | ||
406 | /// Win32 MSI API: | ||
407 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiinstallmissingfile.asp">MsiInstallMissingFile</a> | ||
408 | /// </p></remarks> | ||
409 | public static void InstallMissingFile(string product, string file) | ||
410 | { | ||
411 | uint ret = NativeMethods.MsiInstallMissingFile(product, file); | ||
412 | if (ret != 0) | ||
413 | { | ||
414 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | /// <summary> | ||
419 | /// Reinstalls a feature. | ||
420 | /// </summary> | ||
421 | /// <param name="product">Product code for the product containing the feature to be reinstalled</param> | ||
422 | /// <param name="feature">Feature to be reinstalled</param> | ||
423 | /// <param name="reinstallModes">Reinstall modes</param> | ||
424 | /// <exception cref="InstallCanceledException">the user exited the installation</exception> | ||
425 | /// <remarks><p> | ||
426 | /// Win32 MSI API: | ||
427 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msireinstallfeature.asp">MsiReinstallFeature</a> | ||
428 | /// </p></remarks> | ||
429 | public static void ReinstallFeature(string product, string feature, ReinstallModes reinstallModes) | ||
430 | { | ||
431 | uint ret = NativeMethods.MsiReinstallFeature(product, feature, (uint) reinstallModes); | ||
432 | if (ret != 0) | ||
433 | { | ||
434 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /// <summary> | ||
439 | /// Reinstalls a product. | ||
440 | /// </summary> | ||
441 | /// <param name="product">Product code for the product to be reinstalled</param> | ||
442 | /// <param name="reinstallModes">Reinstall modes</param> | ||
443 | /// <exception cref="InstallCanceledException">the user exited the installation</exception> | ||
444 | /// <remarks><p> | ||
445 | /// Win32 MSI API: | ||
446 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msireinstallproduct.asp">MsiReinstallProduct</a> | ||
447 | /// </p></remarks> | ||
448 | public static void ReinstallProduct(string product, ReinstallModes reinstallModes) | ||
449 | { | ||
450 | uint ret = NativeMethods.MsiReinstallProduct(product, (uint) reinstallModes); | ||
451 | if (ret != 0) | ||
452 | { | ||
453 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /// <summary> | ||
458 | /// Opens an installer package and initializes an install session. | ||
459 | /// </summary> | ||
460 | /// <param name="packagePath">path to the patch package</param> | ||
461 | /// <param name="commandLine">command line property settings</param> | ||
462 | /// <exception cref="InstallerException">There was an error installing the product</exception> | ||
463 | /// <remarks><p> | ||
464 | /// To completely remove a product, set REMOVE=ALL in <paramRef name="commandLine"/>. | ||
465 | /// </p><p> | ||
466 | /// This method displays the user interface with the current settings and | ||
467 | /// log mode. You can change user interface settings with the <see cref="SetInternalUI(InstallUIOptions)"/> | ||
468 | /// and <see cref="SetExternalUI(ExternalUIHandler,InstallLogModes)"/> functions. You can set the log mode with the | ||
469 | /// <see cref="EnableLog(InstallLogModes,string)"/> function. | ||
470 | /// </p><p> | ||
471 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
472 | /// tested after calling this method. | ||
473 | /// </p><p> | ||
474 | /// Win32 MSI API: | ||
475 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiinstallproduct.asp">MsiInstallProduct</a> | ||
476 | /// </p></remarks> | ||
477 | public static void InstallProduct(string packagePath, string commandLine) | ||
478 | { | ||
479 | uint ret = NativeMethods.MsiInstallProduct(packagePath, commandLine); | ||
480 | Installer.CheckInstallResult(ret); | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Installs or uninstalls a product. | ||
485 | /// </summary> | ||
486 | /// <param name="productCode">Product code of the product to be configured.</param> | ||
487 | /// <param name="installLevel">Specifies the default installation configuration of the | ||
488 | /// product. The <paramref name="installLevel"/> parameter is ignored and all features | ||
489 | /// are installed if the <paramref name="installState"/> parameter is set to any other | ||
490 | /// value than <see cref="InstallState.Default"/>. This parameter must be either 0 | ||
491 | /// (install using authored feature levels), 65535 (install all features), or a value | ||
492 | /// between 0 and 65535 to install a subset of available features. </param> | ||
493 | /// <param name="installState">Specifies the installation state for the product.</param> | ||
494 | /// <param name="commandLine">Specifies the command line property settings. This should | ||
495 | /// be a list of the format Property=Setting Property=Setting.</param> | ||
496 | /// <exception cref="InstallerException">There was an error configuring the product</exception> | ||
497 | /// <remarks><p> | ||
498 | /// This method displays the user interface with the current settings and | ||
499 | /// log mode. You can change user interface settings with the <see cref="SetInternalUI(InstallUIOptions)"/> | ||
500 | /// and <see cref="SetExternalUI(ExternalUIHandler,InstallLogModes)"/> functions. You can set the log mode with the | ||
501 | /// <see cref="EnableLog(InstallLogModes,string)"/> function. | ||
502 | /// </p><p> | ||
503 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
504 | /// tested after calling this method. | ||
505 | /// </p><p> | ||
506 | /// Win32 MSI APIs: | ||
507 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiconfigureproduct.asp">MsiConfigureProduct</a>, | ||
508 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiconfigureproductex.asp">MsiConfigureProductEx</a> | ||
509 | /// </p></remarks> | ||
510 | public static void ConfigureProduct(string productCode, int installLevel, InstallState installState, string commandLine) | ||
511 | { | ||
512 | uint ret = NativeMethods.MsiConfigureProductEx(productCode, installLevel, (int) installState, commandLine); | ||
513 | Installer.CheckInstallResult(ret); | ||
514 | } | ||
515 | |||
516 | /// <summary> | ||
517 | /// Configures the installed state for a product feature. | ||
518 | /// </summary> | ||
519 | /// <param name="productCode">Product code of the product to be configured.</param> | ||
520 | /// <param name="feature">Specifies the feature ID for the feature to be configured.</param> | ||
521 | /// <param name="installState">Specifies the installation state for the feature.</param> | ||
522 | /// <exception cref="InstallerException">There was an error configuring the feature</exception> | ||
523 | /// <remarks><p> | ||
524 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
525 | /// tested after calling this method. | ||
526 | /// </p><p> | ||
527 | /// Win32 MSI API: | ||
528 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiconfigurefeature.asp">MsiConfigureFeature</a> | ||
529 | /// </p></remarks> | ||
530 | public static void ConfigureFeature(string productCode, string feature, InstallState installState) | ||
531 | { | ||
532 | uint ret = NativeMethods.MsiConfigureFeature(productCode, feature, (int) installState); | ||
533 | Installer.CheckInstallResult(ret); | ||
534 | } | ||
535 | |||
536 | /// <summary> | ||
537 | /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes | ||
538 | /// an installation and sets the PATCH property to the path of the patch package. | ||
539 | /// </summary> | ||
540 | /// <param name="patchPackage">path to the patch package</param> | ||
541 | /// <param name="commandLine">optional command line property settings</param> | ||
542 | /// <exception cref="InstallerException">There was an error applying the patch</exception> | ||
543 | /// <remarks><p> | ||
544 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
545 | /// tested after calling this method. | ||
546 | /// </p><p> | ||
547 | /// Win32 MSI API: | ||
548 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiapplypatch.asp">MsiApplyPatch</a> | ||
549 | /// </p></remarks> | ||
550 | public static void ApplyPatch(string patchPackage, string commandLine) | ||
551 | { | ||
552 | Installer.ApplyPatch(patchPackage, null, InstallType.Default, commandLine); | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes | ||
557 | /// an installation and sets the PATCH property to the path of the patch package. | ||
558 | /// </summary> | ||
559 | /// <param name="patchPackage">path to the patch package</param> | ||
560 | /// <param name="installPackage">path to the product to be patched, if installType | ||
561 | /// is set to <see cref="InstallType.NetworkImage"/></param> | ||
562 | /// <param name="installType">type of installation to patch</param> | ||
563 | /// <param name="commandLine">optional command line property settings</param> | ||
564 | /// <exception cref="InstallerException">There was an error applying the patch</exception> | ||
565 | /// <remarks><p> | ||
566 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
567 | /// tested after calling this method. | ||
568 | /// </p><p> | ||
569 | /// Win32 MSI API: | ||
570 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiapplypatch.asp">MsiApplyPatch</a> | ||
571 | /// </p></remarks> | ||
572 | public static void ApplyPatch(string patchPackage, string installPackage, InstallType installType, string commandLine) | ||
573 | { | ||
574 | uint ret = NativeMethods.MsiApplyPatch(patchPackage, installPackage, (int) installType, commandLine); | ||
575 | Installer.CheckInstallResult(ret); | ||
576 | } | ||
577 | |||
578 | /// <summary> | ||
579 | /// Removes one or more patches from a single product. To remove a patch from | ||
580 | /// multiple products, RemovePatches must be called for each product. | ||
581 | /// </summary> | ||
582 | /// <param name="patches">List of patches to remove. Each patch can be specified by the GUID | ||
583 | /// of the patch or the full path to the patch package.</param> | ||
584 | /// <param name="productCode">The ProductCode (GUID) of the product from which the patches | ||
585 | /// are removed. This parameter cannot be null.</param> | ||
586 | /// <param name="commandLine">optional command line property settings</param> | ||
587 | /// <exception cref="InstallerException">There was an error removing the patches</exception> | ||
588 | /// <remarks><p> | ||
589 | /// The <see cref="RebootRequired"/> and <see cref="RebootInitiated"/> properties should be | ||
590 | /// tested after calling this method. | ||
591 | /// </p><p> | ||
592 | /// Win32 MSI API: | ||
593 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiremovepatches.asp">MsiRemovePatches</a> | ||
594 | /// </p></remarks> | ||
595 | public static void RemovePatches(IList<string> patches, string productCode, string commandLine) | ||
596 | { | ||
597 | if (patches == null || patches.Count == 0) | ||
598 | { | ||
599 | throw new ArgumentNullException("patches"); | ||
600 | } | ||
601 | |||
602 | if (productCode == null) | ||
603 | { | ||
604 | throw new ArgumentNullException("productCode"); | ||
605 | } | ||
606 | |||
607 | StringBuilder patchList = new StringBuilder(); | ||
608 | foreach (string patch in patches) | ||
609 | { | ||
610 | if (patch != null) | ||
611 | { | ||
612 | if (patchList.Length != 0) | ||
613 | { | ||
614 | patchList.Append(';'); | ||
615 | } | ||
616 | |||
617 | patchList.Append(patch); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | if (patchList.Length == 0) | ||
622 | { | ||
623 | throw new ArgumentNullException("patches"); | ||
624 | } | ||
625 | |||
626 | uint ret = NativeMethods.MsiRemovePatches(patchList.ToString(), productCode, (int) InstallType.SingleInstance, commandLine); | ||
627 | Installer.CheckInstallResult(ret); | ||
628 | } | ||
629 | |||
630 | /// <summary> | ||
631 | /// Determines which patches apply to a specified product MSI and in what sequence. | ||
632 | /// </summary> | ||
633 | /// <param name="productPackage">Full path to an MSI file that is the target product | ||
634 | /// for the set of patches.</param> | ||
635 | /// <param name="patches">An array of strings specifying the patches to be checked. Each item | ||
636 | /// may be the path to an MSP file, the path an XML file, or just an XML blob.</param> | ||
637 | /// <param name="errorHandler">Callback to be invoked for each inapplicable patch, reporting the | ||
638 | /// reason the patch is not applicable. This value may be left null if that information is not | ||
639 | /// desired.</param> | ||
640 | /// <returns>An array of selected patch strings from <paramref name="patches"/>, indicating | ||
641 | /// the set of applicable patches. The items are re-ordered to be in the best sequence.</returns> | ||
642 | /// <remarks><p> | ||
643 | /// If an item in <paramref name="patches"/> is a file path but does not end in .MSP or .XML, | ||
644 | /// it is assumed to be an MSP file. | ||
645 | /// </p><p> | ||
646 | /// As this overload uses InstallContext.None, it does not consider the current state of | ||
647 | /// the system. | ||
648 | /// </p><p> | ||
649 | /// Win32 MSI API: | ||
650 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a> | ||
651 | /// </p></remarks> | ||
652 | public static IList<string> DetermineApplicablePatches( | ||
653 | string productPackage, | ||
654 | string[] patches, | ||
655 | InapplicablePatchHandler errorHandler) | ||
656 | { | ||
657 | return DetermineApplicablePatches(productPackage, patches, errorHandler, null, UserContexts.None); | ||
658 | } | ||
659 | |||
660 | /// <summary> | ||
661 | /// Determines which patches apply to a specified product and in what sequence. If | ||
662 | /// the product is installed, this method accounts for patches that have already been applied to | ||
663 | /// the product and accounts for obsolete and superceded patches. | ||
664 | /// </summary> | ||
665 | /// <param name="product">The product that is the target for the set of patches. This may be | ||
666 | /// either a ProductCode (GUID) of a product that is currently installed, or the path to a an | ||
667 | /// MSI file.</param> | ||
668 | /// <param name="patches">An array of strings specifying the patches to be checked. Each item | ||
669 | /// may be the path to an MSP file, the path an XML file, or just an XML blob.</param> | ||
670 | /// <param name="errorHandler">Callback to be invoked for each inapplicable patch, reporting the | ||
671 | /// reason the patch is not applicable. This value may be left null if that information is not | ||
672 | /// desired.</param> | ||
673 | /// <param name="userSid">Specifies a security identifier (SID) of a user. This parameter restricts | ||
674 | /// the context of enumeration for this user account. This parameter cannot be the special SID | ||
675 | /// strings s-1-1-0 (everyone) or s-1-5-18 (local system). If <paramref name="context"/> is set to | ||
676 | /// <see cref="UserContexts.None"/> or <see cref="UserContexts.Machine"/>, then | ||
677 | /// <paramref name="userSid"/> must be null. For the current user context, <paramref name="userSid"/> | ||
678 | /// can be null and <paramref name="context"/> can be set to <see cref="UserContexts.UserManaged"/> | ||
679 | /// or <see cref="UserContexts.UserUnmanaged"/>.</param> | ||
680 | /// <param name="context">Restricts the enumeration to per-user-unmanaged, per-user-managed, | ||
681 | /// or per-machine context, or (if referring to an MSI) to no system context at all. This | ||
682 | /// parameter can be <see cref="UserContexts.Machine"/>, <see cref="UserContexts.UserManaged"/>, | ||
683 | /// <see cref="UserContexts.UserUnmanaged"/>, or <see cref="UserContexts.None"/>.</param> | ||
684 | /// <returns>An array of selected patch strings from <paramref name="patches"/>, indicating | ||
685 | /// the set of applicable patches. The items are re-ordered to be in the best sequence.</returns> | ||
686 | /// <remarks><p> | ||
687 | /// If an item in <paramref name="patches"/> is a file path but does not end in .MSP or .XML, | ||
688 | /// it is assumed to be an MSP file. | ||
689 | /// </p><p> | ||
690 | /// Passing an InstallContext of None only analyzes the MSI file; it does not consider the | ||
691 | /// current state of the system. You cannot use InstallContext.None with a ProductCode GUID. | ||
692 | /// </p><p> | ||
693 | /// Win32 MSI APIs: | ||
694 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a> | ||
695 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msideterminepatchsequence.asp">MsiDeterminePatchSequence</a> | ||
696 | /// </p></remarks> | ||
697 | public static IList<string> DetermineApplicablePatches( | ||
698 | string product, | ||
699 | string[] patches, | ||
700 | InapplicablePatchHandler errorHandler, | ||
701 | string userSid, | ||
702 | UserContexts context) | ||
703 | { | ||
704 | if (String.IsNullOrEmpty(product)) | ||
705 | { | ||
706 | throw new ArgumentNullException("product"); | ||
707 | } | ||
708 | |||
709 | if (patches == null) | ||
710 | { | ||
711 | throw new ArgumentNullException("patches"); | ||
712 | } | ||
713 | |||
714 | NativeMethods.MsiPatchSequenceData[] sequenceData = new NativeMethods.MsiPatchSequenceData[patches.Length]; | ||
715 | for (int i = 0; i < patches.Length; i++) | ||
716 | { | ||
717 | if (String.IsNullOrEmpty(patches[i])) | ||
718 | { | ||
719 | throw new ArgumentNullException("patches[" + i + "]"); | ||
720 | } | ||
721 | |||
722 | sequenceData[i].szPatchData = patches[i]; | ||
723 | sequenceData[i].ePatchDataType = GetPatchStringDataType(patches[i]); | ||
724 | sequenceData[i].dwOrder = -1; | ||
725 | sequenceData[i].dwStatus = 0; | ||
726 | } | ||
727 | |||
728 | uint ret; | ||
729 | if (context == UserContexts.None) | ||
730 | { | ||
731 | ret = NativeMethods.MsiDetermineApplicablePatches(product, (uint) sequenceData.Length, sequenceData); | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | ret = NativeMethods.MsiDeterminePatchSequence(product, userSid, context, (uint) sequenceData.Length, sequenceData); | ||
736 | } | ||
737 | |||
738 | if (errorHandler != null) | ||
739 | { | ||
740 | for (int i = 0; i < sequenceData.Length; i++) | ||
741 | { | ||
742 | if (sequenceData[i].dwOrder < 0 && sequenceData[i].dwStatus != 0) | ||
743 | { | ||
744 | errorHandler(sequenceData[i].szPatchData, InstallerException.ExceptionFromReturnCode(sequenceData[i].dwStatus)); | ||
745 | } | ||
746 | } | ||
747 | } | ||
748 | |||
749 | if (ret != 0) | ||
750 | { | ||
751 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
752 | } | ||
753 | |||
754 | IList<string> patchSeq = new List<string>(patches.Length); | ||
755 | for (int i = 0; i < sequenceData.Length; i++) | ||
756 | { | ||
757 | for (int j = 0; j < sequenceData.Length; j++) | ||
758 | { | ||
759 | if (sequenceData[j].dwOrder == i) | ||
760 | { | ||
761 | patchSeq.Add(sequenceData[j].szPatchData); | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | return patchSeq; | ||
766 | } | ||
767 | |||
768 | /// <summary> | ||
769 | /// Applies one or more patches to products that are eligible to receive the patch. | ||
770 | /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes | ||
771 | /// an installation and sets the PATCH property to the path of the patch package. | ||
772 | /// </summary> | ||
773 | /// <param name="patchPackages">The set of patch packages to be applied. | ||
774 | /// Each item is the full path to an MSP file.</param> | ||
775 | /// <param name="productCode">Provides the ProductCode of the product being patched. If this parameter | ||
776 | /// is null, the patches are applied to all products that are eligible to receive these patches.</param> | ||
777 | /// <param name="commandLine">optional command line property settings</param> | ||
778 | /// <remarks><p> | ||
779 | /// Win32 MSI API: | ||
780 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiapplymultiplepatches.asp">MsiApplyMultiplePatches</a> | ||
781 | /// </p></remarks> | ||
782 | public static void ApplyMultiplePatches( | ||
783 | IList<string> patchPackages, string productCode, string commandLine) | ||
784 | { | ||
785 | if (patchPackages == null || patchPackages.Count == 0) | ||
786 | { | ||
787 | throw new ArgumentNullException("patchPackages"); | ||
788 | } | ||
789 | |||
790 | StringBuilder patchList = new StringBuilder(); | ||
791 | foreach (string patch in patchPackages) | ||
792 | { | ||
793 | if (patch != null) | ||
794 | { | ||
795 | if (patchList.Length != 0) | ||
796 | { | ||
797 | patchList.Append(';'); | ||
798 | } | ||
799 | |||
800 | patchList.Append(patch); | ||
801 | } | ||
802 | } | ||
803 | |||
804 | if (patchList.Length == 0) | ||
805 | { | ||
806 | throw new ArgumentNullException("patchPackages"); | ||
807 | } | ||
808 | |||
809 | uint ret = NativeMethods.MsiApplyMultiplePatches(patchList.ToString(), productCode, commandLine); | ||
810 | Installer.CheckInstallResult(ret); | ||
811 | } | ||
812 | |||
813 | /// <summary> | ||
814 | /// Extracts information from a patch that can be used to determine whether the patch | ||
815 | /// applies on a target system. The method returns an XML string that can be provided to | ||
816 | /// <see cref="DetermineApplicablePatches(string,string[],InapplicablePatchHandler,string,UserContexts)"/> | ||
817 | /// instead of the full patch file. | ||
818 | /// </summary> | ||
819 | /// <param name="patchPath">Full path to the patch being queried.</param> | ||
820 | /// <returns>XML string containing patch data.</returns> | ||
821 | /// <remarks><p> | ||
822 | /// Win32 MSI API: | ||
823 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiextractpatchxmldata.asp">MsiExtractPatchXMLData</a> | ||
824 | /// </p></remarks> | ||
825 | public static string ExtractPatchXmlData(string patchPath) | ||
826 | { | ||
827 | StringBuilder buf = new StringBuilder(""); | ||
828 | uint bufSize = 0; | ||
829 | uint ret = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize); | ||
830 | if (ret == (uint) NativeMethods.Error.MORE_DATA) | ||
831 | { | ||
832 | buf.Capacity = (int) ++bufSize; | ||
833 | ret = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize); | ||
834 | } | ||
835 | |||
836 | if (ret != 0) | ||
837 | { | ||
838 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
839 | } | ||
840 | return buf.ToString(); | ||
841 | } | ||
842 | |||
843 | /// <summary> | ||
844 | /// [MSI 3.1] Migrates a user's application configuration data to a new SID. | ||
845 | /// </summary> | ||
846 | /// <param name="oldSid">Previous user SID that data is to be migrated from</param> | ||
847 | /// <param name="newSid">New user SID that data is to be migrated to</param> | ||
848 | /// <remarks><p> | ||
849 | /// Win32 MSI API: | ||
850 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msinotifysidchange.asp">MsiNotifySidChange</a> | ||
851 | /// </p></remarks> | ||
852 | public static void NotifySidChange(string oldSid, string newSid) | ||
853 | { | ||
854 | uint ret = NativeMethods.MsiNotifySidChange(oldSid, newSid); | ||
855 | if (ret != 0) | ||
856 | { | ||
857 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | private static void CheckInstallResult(uint ret) | ||
862 | { | ||
863 | switch (ret) | ||
864 | { | ||
865 | case (uint) NativeMethods.Error.SUCCESS: break; | ||
866 | case (uint) NativeMethods.Error.SUCCESS_REBOOT_REQUIRED: Installer.rebootRequired = true; break; | ||
867 | case (uint) NativeMethods.Error.SUCCESS_REBOOT_INITIATED: Installer.rebootInitiated = true; break; | ||
868 | default: throw InstallerException.ExceptionFromReturnCode(ret); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | private static int GetPatchStringDataType(string patchData) | ||
873 | { | ||
874 | if (patchData.IndexOf("<", StringComparison.Ordinal) >= 0 && | ||
875 | patchData.IndexOf(">", StringComparison.Ordinal) >= 0) | ||
876 | { | ||
877 | return 2; // XML blob | ||
878 | } | ||
879 | else if (String.Compare(Path.GetExtension(patchData), ".xml", | ||
880 | StringComparison.OrdinalIgnoreCase) == 0) | ||
881 | { | ||
882 | return 1; // XML file path | ||
883 | } | ||
884 | else | ||
885 | { | ||
886 | return 0; // MSP file path | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | } | ||