#region License // Copyright (c) 2010, Jasper Yeh. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ClearCanvas Inc. nor the names of its contributors // may be used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY // OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using ClearCanvas.Common; using ClearCanvas.Desktop; using Nullstack.ClearCanvasEx.DesktopEx.View.WpfAdapter.Utilities.Backports; namespace Nullstack.ClearCanvasEx.DesktopEx.View.WpfAdapter.Utilities { internal sealed class ViewAdapterExtensionFactory : CustomExtensionFactory { #region Static Init private static readonly ConstructorInfo _ctorDefaultExtensionFactory; private static readonly MethodInfo _methodSetExtensionFactory; private static readonly FieldInfo _fieldAttributeExtensionFilterValues; static ViewAdapterExtensionFactory() { const BindingFlags bindInstance = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; const BindingFlags bindStatic = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static; try { var typeDefaultExtensionFactory = typeof (IExtensionFactory).Assembly.GetType("ClearCanvas.Common.DefaultExtensionFactory"); _ctorDefaultExtensionFactory = typeDefaultExtensionFactory.GetConstructor(bindInstance, null, Type.EmptyTypes, null); _methodSetExtensionFactory = typeof (ExtensionPoint).GetMethod("SetExtensionFactory", bindStatic, null, new[] {typeof (IExtensionFactory)}, null); _fieldAttributeExtensionFilterValues = typeof (AttributeExtensionFilter).GetField("_attributes", bindInstance); } catch (Exception ex) { Platform.Log(LogLevel.Warn, ex, "Failure encountered while reflecting on the ClearCanvas.Common assembly. The WPF View Adapter will be unavailable in this application domain."); } } internal static bool TryInstallExtensionFactory() { if (_methodSetExtensionFactory == null) return false; _methodSetExtensionFactory.Invoke(null, new object[] {new ViewAdapterExtensionFactory()}); return true; } internal static void InstallExtensionFactory() { if (!TryInstallExtensionFactory()) throw new NotSupportedException("The WPF View Adapter is not available."); } #endregion private const string _winformsGuiToolkitId = "WinForms"; private readonly DynamicViewAdapterBuilder _dynamicAdapterBuilder; private readonly IExtensionFactory _defaultExtensionFactory; public ViewAdapterExtensionFactory() { if (_methodSetExtensionFactory == null) throw new NotSupportedException("The WPF View Adapter is not available."); _defaultExtensionFactory = (IExtensionFactory) _ctorDefaultExtensionFactory.Invoke(null); _dynamicAdapterBuilder = new DynamicViewAdapterBuilder("DynamicWpfViewAdapters"); } public override ExtensionInfo[] ListExtensions(ExtensionPoint extensionPoint, ExtensionFilter filter) { Platform.CheckForNullReference(extensionPoint, "extensionPoint"); var results = new List(); results.AddRange(_defaultExtensionFactory.ListExtensions(extensionPoint, filter)); results.AddRange(base.ListExtensions(extensionPoint, filter)); if (results.Count == 0 && IsGuiToolkitExtensionFilter(filter, WpfGuiToolkit.GuiToolkitId)) { TryDefineViewAdapter(extensionPoint.GetType()); results.AddRange(base.ListExtensions(extensionPoint, filter)); } return results.ToArray(); } private void TryDefineViewAdapter(Type extensionPointType) { var result = TryDefineWinFormsViewAdapter(extensionPointType); } private bool TryDefineWinFormsViewAdapter(Type extensionPointType) { try { var extensionPointInstance = (IExtensionPoint) Activator.CreateInstance(extensionPointType); var extensionInstance = extensionPointInstance.CreateExtension(GetGuiToolkitExtensionFilter(_winformsGuiToolkitId)); var extensionType = extensionInstance.GetType(); var adapterBase = GetViewAdapterBase(extensionType); var adapterType = _dynamicAdapterBuilder.CreateExtension(string.Format("{0}WpfViewAdapter", extensionType.FullName), extensionPointType, extensionType, adapterBase, new Type[] {}); Define(extensionPointType, adapterType); return true; } catch (NotSupportedException ex) { Platform.Log(LogLevel.Debug, ex, "No extensions to adapt."); } catch (Exception ex) { Platform.Log(LogLevel.Warn, ex, "Failed to create WPF view extension adapter."); } return false; } private static Type GetViewAdapterBase(Type viewType) { if (typeof (IApplicationComponentView).IsAssignableFrom(viewType)) return typeof (ApplicationComponentViewAdapter<>).MakeGenericType(viewType); throw new NotSupportedException(string.Format("No WPF View Adapter is available for the type {0}", viewType)); } private static ExtensionFilter GetGuiToolkitExtensionFilter(string guiToolkitId) { if (string.IsNullOrEmpty(guiToolkitId)) throw new ArgumentNullException("guiToolkitId"); return new AttributeExtensionFilter(new GuiToolkitAttribute(guiToolkitId)); } private static bool IsGuiToolkitExtensionFilter(ExtensionFilter filter, string guiToolkitId) { if (_fieldAttributeExtensionFilterValues == null) return false; if (filter is AttributeExtensionFilter) { var attributes = (Attribute[]) _fieldAttributeExtensionFilterValues.GetValue(filter); if (attributes != null && attributes.Length == 1) { if (string.IsNullOrEmpty(guiToolkitId)) return true; return new GuiToolkitAttribute(guiToolkitId).Match(attributes[0]); } } return false; } private class DynamicViewAdapterBuilder : DynamicAdapterBuilder { public DynamicViewAdapterBuilder(string assemblyName) : base(assemblyName) {} public Type CreateExtension(string name, Type extensionPoint, Type source, Type @base, IEnumerable interfaces) { return DefineAdapter(name, source, @base, interfaces, ExtensionOfMaker(extensionPoint)); } public void ExportAssembly(string filename) { AssemblyBuilder.Save(filename); } private static IEnumerable ExtensionOfMaker(Type extensionPoint) { var ctor = typeof (ExtensionOfAttribute).GetConstructor(new[] {typeof (Type)}); var cab = new CustomAttributeBuilder(ctor, new[] {extensionPoint}); yield return cab; } } } }