public static int InvokeCustomAction(int sessionHandle, string entryPoint, IntPtr remotingDelegatePtr) { Session session = null; string assemblyName, className, methodName; MethodInfo method; try { MsiRemoteInvoke remotingDelegate = (MsiRemoteInvoke) Marshal.GetDelegateForFunctionPointer( remotingDelegatePtr, typeof(MsiRemoteInvoke)); RemotableNativeMethods.RemotingDelegate = remotingDelegate; sessionHandle = RemotableNativeMethods.MakeRemoteHandle(sessionHandle); session = new Session((IntPtr) sessionHandle, false); if (string.IsNullOrWhiteSpace(entryPoint)) { throw new ArgumentNullException("entryPoint"); } if (!CustomActionProxy.FindEntryPoint( session, entryPoint, out assemblyName, out className, out methodName)) { return (int) ActionResult.Failure; } session.Log("Calling custom action {0}!{1}.{2}", assemblyName, className, methodName); method = CustomActionProxy.GetCustomActionMethod( session, assemblyName, className, methodName); if (method == null) { return (int) ActionResult.Failure; } } catch (Exception ex) { if (session != null) { try { session.Log("Exception while loading custom action:"); session.Log(ex.ToString()); } catch (Exception) { } } return (int) ActionResult.Failure; } try { // Set the current directory to the location of the extracted files. Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); object[] args = new object[] { session }; if (DebugBreakEnabled(new string[] { entryPoint, methodName })) { string message = String.Format(CultureInfo.InvariantCulture, "To debug your custom action, attach to process ID {0} (0x{0:x}) and click OK; otherwise, click Cancel to fail the custom action.", System.Diagnostics.Process.GetCurrentProcess().Id ); MessageResult button = NativeMethods.MessageBox( IntPtr.Zero, message, "Custom Action Breakpoint", (int)MessageButtons.OKCancel | (int)MessageIcon.Asterisk | (int)(MessageBoxStyles.TopMost | MessageBoxStyles.ServiceNotification) ); if (MessageResult.Cancel == button) { return (int)ActionResult.UserExit; } } ActionResult result = (ActionResult) method.Invoke(null, args); session.Close(); return (int) result; } catch (InstallCanceledException) { return (int) ActionResult.UserExit; } catch (Exception ex) { session.Log("Exception thrown by custom action:"); session.Log(ex.ToString()); return (int) ActionResult.Failure; } }
private static MethodInfo GetCustomActionMethod( Session session, string assemblyName, string className, string methodName) { Assembly customActionAssembly; Type customActionClass = null; Exception caughtEx = null; try { customActionAssembly = AppDomain.CurrentDomain.Load(assemblyName); customActionClass = customActionAssembly.GetType(className, true, true); } catch (IOException ex) { caughtEx = ex; } catch (BadImageFormatException ex) { caughtEx = ex; } catch (TypeLoadException ex) { caughtEx = ex; } catch (ReflectionTypeLoadException ex) { caughtEx = ex; } catch (SecurityException ex) { caughtEx = ex; } if (caughtEx != null) { session.Log("Error: could not load custom action class " + className + " from assembly: " + assemblyName); session.Log(caughtEx.ToString()); return null; } MethodInfo[] methods = customActionClass.GetMethods( BindingFlags.Public | BindingFlags.Static); foreach (MethodInfo method in methods) { if (method.Name == methodName && CustomActionProxy.MethodHasCustomActionSignature(method)) { return method; } } session.Log("Error: custom action method \"" + methodName + "\" is missing or has the wrong signature."); return null; }
public static int Initialize(int sessionHandle, string uiClass, int internalUILevel) { Session session = null; try { session = new Session((IntPtr) sessionHandle, false); if (string.IsNullOrWhiteSpace(uiClass)) { throw new ArgumentNullException("uiClass"); } EmbeddedUIProxy.uiInstance = EmbeddedUIProxy.InstantiateUI(session, uiClass); } catch (Exception ex) { if (session != null) { try { session.Log("Exception while loading embedded UI:"); session.Log(ex.ToString()); } catch (Exception) { } } } if (EmbeddedUIProxy.uiInstance == null) { return (int) ActionResult.Failure; } try { string resourcePath = Path.GetDirectoryName(EmbeddedUIProxy.uiInstance.GetType().Assembly.Location); InstallUIOptions uiOptions = (InstallUIOptions) internalUILevel; if (EmbeddedUIProxy.DebugBreakEnabled("Initialize")) { System.Diagnostics.Debugger.Launch(); } if (EmbeddedUIProxy.uiInstance.Initialize(session, resourcePath, ref uiOptions)) { // The embedded UI initialized and the installation should continue // with internal UI reset according to options. return ((int) uiOptions) << 16; } else { // The embedded UI did not initialize but the installation should still continue // with internal UI reset according to options. return (int) uiOptions; } } catch (InstallCanceledException) { // The installation was canceled by the user. return (int) ActionResult.UserExit; } catch (Exception ex) { // An unhandled exception causes the installation to fail immediately. session.Log("Exception thrown by embedded UI initialization:"); session.Log(ex.ToString()); return (int) ActionResult.Failure; } }
private static bool FindEntryPoint( Session session, string entryPoint, out string assemblyName, out string className, out string methodName) { assemblyName = null; className = null; methodName = null; string fullEntryPoint; if (entryPoint.IndexOf('!') > 0) { fullEntryPoint = entryPoint; } else { IDictionary config; try { config = (IDictionary) ConfigurationManager.GetSection("customActions"); } catch (ConfigurationException cex) { session.Log("Error: missing or invalid customActions config section."); session.Log(cex.ToString()); return false; } fullEntryPoint = (string) config[entryPoint]; if (fullEntryPoint == null) { session.Log( "Error: custom action entry point '{0}' not found " + "in customActions config section.", entryPoint); return false; } } int assemblySplit = fullEntryPoint.IndexOf('!'); int methodSplit = fullEntryPoint.LastIndexOf('.'); if (assemblySplit < 0 || methodSplit < 0 || methodSplit < assemblySplit) { session.Log("Error: invalid custom action entry point:" + entryPoint); return false; } assemblyName = fullEntryPoint.Substring(0, assemblySplit); className = fullEntryPoint.Substring(assemblySplit + 1, methodSplit - assemblySplit - 1); methodName = fullEntryPoint.Substring(methodSplit + 1); return true; }
private static IEmbeddedUI InstantiateUI(Session session, string uiClass) { int assemblySplit = uiClass.IndexOf('!'); if (assemblySplit < 0) { session.Log("Error: invalid embedded UI assembly and class:" + uiClass); return null; } string assemblyName = uiClass.Substring(0, assemblySplit); EmbeddedUIProxy.uiClass = uiClass.Substring(assemblySplit + 1); Assembly uiAssembly; try { uiAssembly = AppDomain.CurrentDomain.Load(assemblyName); // This calls out to CustomActionProxy.DebugBreakEnabled() directly instead // of calling EmbeddedUIProxy.DebugBreakEnabled() because we don't compose a // class.method name for this breakpoint. if (CustomActionProxy.DebugBreakEnabled(new string[] { "EmbeddedUI" })) { System.Diagnostics.Debugger.Launch(); } return (IEmbeddedUI) uiAssembly.CreateInstance(EmbeddedUIProxy.uiClass); } catch (Exception ex) { session.Log("Error: could not load embedded UI class " + EmbeddedUIProxy.uiClass + " from assembly: " + assemblyName); session.Log(ex.ToString()); return null; } }