aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.WindowsInstaller/EmbeddedUIProxy.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.WindowsInstaller/EmbeddedUIProxy.cs231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/EmbeddedUIProxy.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/EmbeddedUIProxy.cs
new file mode 100644
index 00000000..05e910d4
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/EmbeddedUIProxy.cs
@@ -0,0 +1,231 @@
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
3namespace WixToolset.Dtf.WindowsInstaller
4{
5 using System;
6 using System.Collections;
7 using System.Configuration;
8 using System.Diagnostics.CodeAnalysis;
9 using System.IO;
10 using System.Reflection;
11 using System.Runtime.InteropServices;
12 using System.Security;
13 using System.Text;
14
15 /// <summary>
16 /// Managed-code portion of the embedded UI proxy.
17 /// </summary>
18 internal static class EmbeddedUIProxy
19 {
20 private static IEmbeddedUI uiInstance;
21 private static string uiClass;
22
23 private static bool DebugBreakEnabled(string method)
24 {
25 return CustomActionProxy.DebugBreakEnabled(new string[] { method, EmbeddedUIProxy.uiClass + "." + method } );
26 }
27
28 /// <summary>
29 /// Initializes managed embedded UI by loading the UI class and invoking its Initialize method.
30 /// </summary>
31 /// <param name="sessionHandle">Integer handle to the installer session.</param>
32 /// <param name="uiClass">Name of the class that implements the embedded UI. This must
33 /// be of the form: &quot;AssemblyName!Namespace.Class&quot;</param>
34 /// <param name="internalUILevel">On entry, contains the current UI level for the installation. After this
35 /// method returns, the installer resets the UI level to the returned value of this parameter.</param>
36 /// <returns>0 if the embedded UI was successfully loaded and initialized,
37 /// ERROR_INSTALL_USEREXIT if the user canceled the installation during initialization,
38 /// or ERROR_INSTALL_FAILURE if the embedded UI could not be initialized.</returns>
39 /// <remarks>
40 /// Due to interop limitations, the successful resulting UILevel is actually returned
41 /// as the high-word of the return value instead of via a ref parameter.
42 /// </remarks>
43 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
44 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
45 public static int Initialize(int sessionHandle, string uiClass, int internalUILevel)
46 {
47 Session session = null;
48
49 try
50 {
51 session = new Session((IntPtr) sessionHandle, false);
52
53 if (String.IsNullOrEmpty(uiClass))
54 {
55 throw new ArgumentNullException("uiClass");
56 }
57
58 EmbeddedUIProxy.uiInstance = EmbeddedUIProxy.InstantiateUI(session, uiClass);
59 }
60 catch (Exception ex)
61 {
62 if (session != null)
63 {
64 try
65 {
66 session.Log("Exception while loading embedded UI:");
67 session.Log(ex.ToString());
68 }
69 catch (Exception)
70 {
71 }
72 }
73 }
74
75 if (EmbeddedUIProxy.uiInstance == null)
76 {
77 return (int) ActionResult.Failure;
78 }
79
80 try
81 {
82 string resourcePath = Path.GetDirectoryName(EmbeddedUIProxy.uiInstance.GetType().Assembly.Location);
83 InstallUIOptions uiOptions = (InstallUIOptions) internalUILevel;
84 if (EmbeddedUIProxy.DebugBreakEnabled("Initialize"))
85 {
86 System.Diagnostics.Debugger.Launch();
87 }
88
89 if (EmbeddedUIProxy.uiInstance.Initialize(session, resourcePath, ref uiOptions))
90 {
91 // The embedded UI initialized and the installation should continue
92 // with internal UI reset according to options.
93 return ((int) uiOptions) << 16;
94 }
95 else
96 {
97 // The embedded UI did not initialize but the installation should still continue
98 // with internal UI reset according to options.
99 return (int) uiOptions;
100 }
101 }
102 catch (InstallCanceledException)
103 {
104 // The installation was canceled by the user.
105 return (int) ActionResult.UserExit;
106 }
107 catch (Exception ex)
108 {
109 // An unhandled exception causes the installation to fail immediately.
110 session.Log("Exception thrown by embedded UI initialization:");
111 session.Log(ex.ToString());
112 return (int) ActionResult.Failure;
113 }
114 }
115
116 /// <summary>
117 /// Passes a progress message to the UI class.
118 /// </summary>
119 /// <param name="messageType">Installer message type and message box options.</param>
120 /// <param name="recordHandle">Handle to a record containing message data.</param>
121 /// <returns>Return value returned by the UI class.</returns>
122 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
123 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
124 public static int ProcessMessage(int messageType, int recordHandle)
125 {
126 if (EmbeddedUIProxy.uiInstance != null)
127 {
128 try
129 {
130 int msgType = messageType & 0x7F000000;
131 int buttons = messageType & 0x0000000F;
132 int icon = messageType & 0x000000F0;
133 int defButton = messageType & 0x00000F00;
134
135 Record msgRec = (recordHandle != 0 ? Record.FromHandle((IntPtr) recordHandle, false) : null);
136 using (msgRec)
137 {
138 if (EmbeddedUIProxy.DebugBreakEnabled("ProcessMessage"))
139 {
140 System.Diagnostics.Debugger.Launch();
141 }
142
143 return (int) EmbeddedUIProxy.uiInstance.ProcessMessage(
144 (InstallMessage) msgType,
145 msgRec,
146 (MessageButtons) buttons,
147 (MessageIcon) icon,
148 (MessageDefaultButton) defButton);
149 }
150 }
151 catch (Exception)
152 {
153 // Ignore it... just hope future messages will not throw exceptions.
154 }
155 }
156
157 return 0;
158 }
159
160 /// <summary>
161 /// Passes a shutdown message to the UI class.
162 /// </summary>
163 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
164 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
165 public static void Shutdown()
166 {
167 if (EmbeddedUIProxy.uiInstance != null)
168 {
169 try
170 {
171 if (EmbeddedUIProxy.DebugBreakEnabled("Shutdown"))
172 {
173 System.Diagnostics.Debugger.Launch();
174 }
175
176 EmbeddedUIProxy.uiInstance.Shutdown();
177 }
178 catch (Exception)
179 {
180 // Nothing to do at this point... the installation is done anyway.
181 }
182
183 EmbeddedUIProxy.uiInstance = null;
184 }
185 }
186
187 /// <summary>
188 /// Instantiates a UI class from a given assembly and class name.
189 /// </summary>
190 /// <param name="session">Installer session, for logging.</param>
191 /// <param name="uiClass">Name of the class that implements the embedded UI. This must
192 /// be of the form: &quot;AssemblyName!Namespace.Class&quot;</param>
193 /// <returns>Interface on the UI class for handling UI messages.</returns>
194 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
195 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
196 private static IEmbeddedUI InstantiateUI(Session session, string uiClass)
197 {
198 int assemblySplit = uiClass.IndexOf('!');
199 if (assemblySplit < 0)
200 {
201 session.Log("Error: invalid embedded UI assembly and class:" + uiClass);
202 return null;
203 }
204
205 string assemblyName = uiClass.Substring(0, assemblySplit);
206 EmbeddedUIProxy.uiClass = uiClass.Substring(assemblySplit + 1);
207
208 Assembly uiAssembly;
209 try
210 {
211 uiAssembly = AppDomain.CurrentDomain.Load(assemblyName);
212
213 // This calls out to CustomActionProxy.DebugBreakEnabled() directly instead
214 // of calling EmbeddedUIProxy.DebugBreakEnabled() because we don't compose a
215 // class.method name for this breakpoint.
216 if (CustomActionProxy.DebugBreakEnabled(new string[] { "EmbeddedUI" }))
217 {
218 System.Diagnostics.Debugger.Launch();
219 }
220
221 return (IEmbeddedUI) uiAssembly.CreateInstance(EmbeddedUIProxy.uiClass);
222 }
223 catch (Exception ex)
224 {
225 session.Log("Error: could not load embedded UI class " + EmbeddedUIProxy.uiClass + " from assembly: " + assemblyName);
226 session.Log(ex.ToString());
227 return null;
228 }
229 }
230 }
231}