7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
using System.Reflection;
32
using System.Collections;
33
using System.Collections.Generic;
35
using Mono.Addins.Localization;
40
/// Provides access to add-in and extension model management operations.
42
public class AddinManager
44
static AddinEngine sessionService;
46
private AddinManager ()
51
/// Initializes the add-in engine.
54
/// The add-in engine needs to be initialized before doing any add-in operation.
55
/// When initialized with this method, it will look for add-ins in the global add-in registry.
57
public static void Initialize ()
59
// Code not shared with the other Initialize since I need to get the calling assembly
60
Assembly asm = Assembly.GetEntryAssembly ();
61
if (asm == null) asm = Assembly.GetCallingAssembly ();
62
AddinEngine.Initialize (asm, null, null, null);
66
/// Initializes the add-in engine.
68
/// <param name="configDir">
69
/// Location of the add-in registry.
72
/// The add-in engine needs to be initialized before doing any add-in operation.
73
/// Configuration information about the add-in registry will be stored in the
74
/// provided location. The add-in engine will look for add-ins in an 'addins'
75
/// subdirectory of the provided directory.
77
/// When specifying a path, it is possible to use a special folder name as root.
78
/// For example: [Personal]/.config/MyApp. In this case, [Personal] will be replaced
79
/// by the location of the Environment.SpecialFolder.Personal folder. Any value
80
/// of the Environment.SpecialFolder enumeration can be used (always between square
83
public static void Initialize (string configDir)
85
Assembly asm = Assembly.GetEntryAssembly ();
86
if (asm == null) asm = Assembly.GetCallingAssembly ();
87
AddinEngine.Initialize (asm, configDir, null, null);
91
/// Initializes the add-in engine.
93
/// <param name='configDir'>
94
/// Location of the add-in registry.
96
/// <param name='addinsDir'>
97
/// Add-ins directory. If the path is relative, it is considered to be relative
98
/// to the configDir directory.
101
/// The add-in engine needs to be initialized before doing any add-in operation.
102
/// Configuration information about the add-in registry will be stored in the
103
/// provided location. The add-in engine will look for add-ins in the provided
104
/// 'addinsDir' directory.
106
/// When specifying a path, it is possible to use a special folder name as root.
107
/// For example: [Personal]/.config/MyApp. In this case, [Personal] will be replaced
108
/// by the location of the Environment.SpecialFolder.Personal folder. Any value
109
/// of the Environment.SpecialFolder enumeration can be used (always between square
112
public static void Initialize (string configDir, string addinsDir)
114
Assembly asm = Assembly.GetEntryAssembly ();
115
if (asm == null) asm = Assembly.GetCallingAssembly ();
116
AddinEngine.Initialize (asm, configDir, addinsDir, null);
120
/// Initializes the add-in engine.
122
/// <param name='configDir'>
123
/// Location of the add-in registry.
125
/// <param name='addinsDir'>
126
/// Add-ins directory. If the path is relative, it is considered to be relative
127
/// to the configDir directory.
129
/// <param name='databaseDir'>
130
/// Location of the add-in database. If the path is relative, it is considered to be relative
131
/// to the configDir directory.
134
/// The add-in engine needs to be initialized before doing any add-in operation.
135
/// Configuration information about the add-in registry will be stored in the
136
/// provided location. The add-in engine will look for add-ins in the provided
137
/// 'addinsDir' directory. Cached information about add-ins will be stored in
138
/// the 'databaseDir' directory.
140
/// When specifying a path, it is possible to use a special folder name as root.
141
/// For example: [Personal]/.config/MyApp. In this case, [Personal] will be replaced
142
/// by the location of the Environment.SpecialFolder.Personal folder. Any value
143
/// of the Environment.SpecialFolder enumeration can be used (always between square
146
public static void Initialize (string configDir, string addinsDir, string databaseDir)
148
Assembly asm = Assembly.GetEntryAssembly ();
149
if (asm == null) asm = Assembly.GetCallingAssembly ();
150
AddinEngine.Initialize (asm, configDir, addinsDir, databaseDir);
154
/// Finalizes an add-in engine.
156
public static void Shutdown ()
158
AddinEngine.Shutdown ();
162
/// Sets the default localizer to be used for this add-in engine
164
/// <param name="localizer">
165
/// The add-in localizer
167
public static void InitializeDefaultLocalizer (IAddinLocalizer localizer)
169
AddinEngine.InitializeDefaultLocalizer (localizer);
172
internal static string StartupDirectory {
173
get { return AddinEngine.StartupDirectory; }
177
/// Gets whether the add-in engine has been initialized.
179
public static bool IsInitialized {
180
get { return AddinEngine.IsInitialized; }
184
/// Gets the default add-in installer
187
/// The default installer is used by the CheckInstalled method to request
188
/// the installation of missing add-ins.
190
public static IAddinInstaller DefaultInstaller {
191
get { return AddinEngine.DefaultInstaller; }
192
set { AddinEngine.DefaultInstaller = value; }
196
/// Gets the default localizer for this add-in engine
198
public static AddinLocalizer DefaultLocalizer {
200
return AddinEngine.DefaultLocalizer;
205
/// Gets the localizer for the add-in that is invoking this property
207
public static AddinLocalizer CurrentLocalizer {
209
AddinEngine.CheckInitialized ();
210
RuntimeAddin addin = AddinEngine.GetAddinForAssembly (Assembly.GetCallingAssembly ());
212
return addin.Localizer;
214
return AddinEngine.DefaultLocalizer;
219
/// Gets a reference to the RuntimeAddin object for the add-in that is invoking this property
221
public static RuntimeAddin CurrentAddin {
223
AddinEngine.CheckInitialized ();
224
return AddinEngine.GetAddinForAssembly (Assembly.GetCallingAssembly ());
229
/// Gets the default add-in engine
231
public static AddinEngine AddinEngine {
233
if (sessionService == null)
234
sessionService = new AddinEngine();
236
return sessionService;
241
/// Gets the add-in registry bound to the default add-in engine
243
public static AddinRegistry Registry {
245
return AddinEngine.Registry;
250
/// Checks if the provided add-ins are installed, and requests the installation of those
253
/// <param name="message">
254
/// Message to show to the user when new add-ins have to be installed.
256
/// <param name="addinIds">
257
/// List of IDs of the add-ins to be checked.
260
/// This method checks if the specified add-ins are installed.
261
/// If some of the add-ins are not installed, it will use
262
/// the installer assigned to the DefaultAddinInstaller property
263
/// to install them. If the installation fails, or if DefaultAddinInstaller
264
/// is not set, an exception will be thrown.
266
public static void CheckInstalled (string message, params string[] addinIds)
268
AddinEngine.CheckInstalled (message, addinIds);
272
/// Checks if an add-in has been loaded.
274
/// <param name="id">
275
/// Full identifier of the add-in.
278
/// True if the add-in is loaded.
280
public static bool IsAddinLoaded (string id)
282
return AddinEngine.IsAddinLoaded (id);
286
/// Forces the loading of an add-in.
288
/// <param name="statusMonitor">
289
/// Status monitor to keep track of the loading process.
291
/// <param name="id">
292
/// Full identifier of the add-in to load.
295
/// This method loads all assemblies that belong to an add-in in memory.
296
/// All add-ins on which the specified add-in depends will also be loaded.
297
/// Notice that in general add-ins don't need to be explicitely loaded using
298
/// this method, since the add-in engine will load them on demand.
300
public static void LoadAddin (IProgressStatus statusMonitor, string id)
302
AddinEngine.LoadAddin (statusMonitor, id);
306
/// Creates a new extension context.
309
/// The new extension context.
312
/// Extension contexts can be used to query the extension model using particular condition values.
314
public static ExtensionContext CreateExtensionContext ()
316
return AddinEngine.CreateExtensionContext ();
320
/// Returns the extension node in a path
322
/// <param name="path">
323
/// Location of the node.
326
/// The node, or null if not found.
328
public static ExtensionNode GetExtensionNode (string path)
330
AddinEngine.CheckInitialized ();
331
return AddinEngine.GetExtensionNode (path);
335
/// Returns the extension node in a path
337
/// <param name="path">
338
/// Location of the node.
341
/// The node, or null if not found.
343
public static T GetExtensionNode<T> (string path) where T:ExtensionNode
345
AddinEngine.CheckInitialized ();
346
return AddinEngine.GetExtensionNode<T> (path);
350
/// Gets extension nodes registered in a path.
352
/// <param name="path">
353
/// An extension path.>
356
/// All nodes registered in the provided path.
358
public static ExtensionNodeList GetExtensionNodes (string path)
360
AddinEngine.CheckInitialized ();
361
return AddinEngine.GetExtensionNodes (path);
365
/// Gets extension nodes registered in a path.
367
/// <param name="path">
368
/// An extension path.
370
/// <param name="expectedNodeType">
371
/// Expected node type.
377
/// This method returns all nodes registered under the provided path.
378
/// It will throw a InvalidOperationException if the type of one of
379
/// the registered nodes is not assignable to the provided type.
381
public static ExtensionNodeList GetExtensionNodes (string path, Type expectedNodeType)
383
AddinEngine.CheckInitialized ();
384
return AddinEngine.GetExtensionNodes (path, expectedNodeType);
388
/// Gets extension nodes registered in a path.
390
/// <param name="path">
391
/// An extension path.
397
/// This method returns all nodes registered under the provided path.
398
/// It will throw a InvalidOperationException if the type of one of
399
/// the registered nodes is not assignable to the provided type.
401
public static ExtensionNodeList<T> GetExtensionNodes<T> (string path) where T:ExtensionNode
403
AddinEngine.CheckInitialized ();
404
return AddinEngine.GetExtensionNodes<T> (path);
408
/// Gets extension nodes for a type extension point
410
/// <param name="instanceType">
411
/// Type defining the extension point
417
/// This method returns all extension nodes bound to the provided type.
419
public static ExtensionNodeList GetExtensionNodes (Type instanceType)
421
AddinEngine.CheckInitialized ();
422
return AddinEngine.GetExtensionNodes (instanceType);
426
/// Gets extension nodes for a type extension point
428
/// <param name="instanceType">
429
/// Type defining the extension point
431
/// <param name="expectedNodeType">
432
/// Expected extension node type
438
/// This method returns all nodes registered for the provided type.
439
/// It will throw a InvalidOperationException if the type of one of
440
/// the registered nodes is not assignable to the provided node type.
442
public static ExtensionNodeList GetExtensionNodes (Type instanceType, Type expectedNodeType)
444
AddinEngine.CheckInitialized ();
445
return AddinEngine.GetExtensionNodes (instanceType, expectedNodeType);
449
/// Gets extension nodes for a type extension point
451
/// <param name="instanceType">
452
/// Type defining the extension point
458
/// This method returns all nodes registered for the provided type.
459
/// It will throw a InvalidOperationException if the type of one of
460
/// the registered nodes is not assignable to the specified node type argument.
462
public static ExtensionNodeList<T> GetExtensionNodes<T> (Type instanceType) where T: ExtensionNode
464
AddinEngine.CheckInitialized ();
465
return AddinEngine.GetExtensionNodes<T> (instanceType);
469
/// Gets extension objects registered for a type extension point.
471
/// <param name="instanceType">
472
/// Type defining the extension point
475
/// A list of objects
477
public static object[] GetExtensionObjects (Type instanceType)
479
AddinEngine.CheckInitialized ();
480
return AddinEngine.GetExtensionObjects (instanceType);
484
/// Gets extension objects registered for a type extension point.
487
/// A list of objects
490
/// The type argument of this generic method is the type that defines
491
/// the extension point.
493
public static T[] GetExtensionObjects<T> ()
495
AddinEngine.CheckInitialized ();
496
return AddinEngine.GetExtensionObjects<T> ();
500
/// Gets extension objects registered for a type extension point.
502
/// <param name="instanceType">
503
/// Type defining the extension point
505
/// <param name="reuseCachedInstance">
506
/// When set to True, it will return instances created in previous calls.
509
/// A list of extension objects.
511
public static object[] GetExtensionObjects (Type instanceType, bool reuseCachedInstance)
513
AddinEngine.CheckInitialized ();
514
return AddinEngine.GetExtensionObjects (instanceType, reuseCachedInstance);
518
/// Gets extension objects registered for a type extension point.
520
/// <param name="reuseCachedInstance">
521
/// When set to True, it will return instances created in previous calls.
524
/// A list of extension objects.
527
/// The type argument of this generic method is the type that defines
528
/// the extension point.
530
public static T[] GetExtensionObjects<T> (bool reuseCachedInstance)
532
AddinEngine.CheckInitialized ();
533
return AddinEngine.GetExtensionObjects<T> (reuseCachedInstance);
537
/// Gets extension objects registered in a path
539
/// <param name="path">
540
/// An extension path.
543
/// An array of objects registered in the path.
546
/// This method can only be used if all nodes in the provided extension path
547
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
548
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
549
/// method for each node.
551
public static object[] GetExtensionObjects (string path)
553
AddinEngine.CheckInitialized ();
554
return AddinEngine.GetExtensionObjects (path);
558
/// Gets extension objects registered in a path.
560
/// <param name="path">
561
/// An extension path.
563
/// <param name="reuseCachedInstance">
564
/// When set to True, it will return instances created in previous calls.
567
/// An array of objects registered in the path.
570
/// This method can only be used if all nodes in the provided extension path
571
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
572
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
573
/// method for each node (or TypeExtensionNode.GetInstance() if
574
/// reuseCachedInstance is set to true)
576
public static object[] GetExtensionObjects (string path, bool reuseCachedInstance)
578
AddinEngine.CheckInitialized ();
579
return AddinEngine.GetExtensionObjects (path, reuseCachedInstance);
583
/// Gets extension objects registered in a path.
585
/// <param name="path">
586
/// An extension path.
588
/// <param name="arrayElementType">
589
/// Type of the return array elements.
592
/// An array of objects registered in the path.
595
/// This method can only be used if all nodes in the provided extension path
596
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
597
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
598
/// method for each node.
600
/// An InvalidOperationException exception is thrown if one of the found
601
/// objects is not a subclass of the provided type.
603
public static object[] GetExtensionObjects (string path, Type arrayElementType)
605
AddinEngine.CheckInitialized ();
606
return AddinEngine.GetExtensionObjects (path, arrayElementType);
610
/// Gets extension objects registered in a path.
612
/// <param name="path">
613
/// An extension path.
616
/// An array of objects registered in the path.
619
/// This method can only be used if all nodes in the provided extension path
620
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
621
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
622
/// method for each node.
624
/// An InvalidOperationException exception is thrown if one of the found
625
/// objects is not a subclass of the provided type.
627
public static T[] GetExtensionObjects<T> (string path)
629
AddinEngine.CheckInitialized ();
630
return AddinEngine.GetExtensionObjects<T> (path);
634
/// Gets extension objects registered in a path.
636
/// <param name="path">
637
/// An extension path.
639
/// <param name="arrayElementType">
640
/// Type of the return array elements.
642
/// <param name="reuseCachedInstance">
643
/// When set to True, it will return instances created in previous calls.
646
/// An array of objects registered in the path.
649
/// This method can only be used if all nodes in the provided extension path
650
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
651
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
652
/// method for each node (or TypeExtensionNode.GetInstance() if
653
/// reuseCachedInstance is set to true).
655
/// An InvalidOperationException exception is thrown if one of the found
656
/// objects is not a subclass of the provided type.
658
public static object[] GetExtensionObjects (string path, Type arrayElementType, bool reuseCachedInstance)
660
AddinEngine.CheckInitialized ();
661
return AddinEngine.GetExtensionObjects (path, arrayElementType, reuseCachedInstance);
665
/// Gets extension objects registered in a path.
667
/// <param name="path">
668
/// An extension path.
670
/// <param name="reuseCachedInstance">
671
/// When set to True, it will return instances created in previous calls.
674
/// An array of objects registered in the path.
677
/// This method can only be used if all nodes in the provided extension path
678
/// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
679
/// by all objects created by calling the TypeExtensionNode.CreateInstance()
680
/// method for each node (or TypeExtensionNode.GetInstance() if
681
/// reuseCachedInstance is set to true).
683
/// An InvalidOperationException exception is thrown if one of the found
684
/// objects is not a subclass of the provided type.
686
public static T[] GetExtensionObjects<T> (string path, bool reuseCachedInstance)
688
AddinEngine.CheckInitialized ();
689
return AddinEngine.GetExtensionObjects<T> (path, reuseCachedInstance);
693
/// Extension change event.
696
/// This event is fired when any extension point in the add-in system changes.
697
/// The event args object provides the path of the changed extension, although
698
/// it does not provide information about what changed. Hosts subscribing to
699
/// this event should get the new list of nodes using a query method such as
700
/// AddinManager.GetExtensionNodes() and then update whatever needs to be updated.
702
public static event ExtensionEventHandler ExtensionChanged {
703
add { AddinEngine.CheckInitialized(); AddinEngine.ExtensionChanged += value; }
704
remove { AddinEngine.CheckInitialized(); AddinEngine.ExtensionChanged -= value; }
708
/// Register a listener of extension node changes.
710
/// <param name="path">
711
/// Path of the node.
713
/// <param name="handler">
714
/// A handler method.
717
/// Hosts can call this method to be subscribed to an extension change
718
/// event for a specific path. The event will be fired once for every
719
/// individual node change. The event arguments include the change type
720
/// (Add or Remove) and the extension node added or removed.
722
/// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
724
public static void AddExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
726
AddinEngine.CheckInitialized ();
727
AddinEngine.AddExtensionNodeHandler (path, handler);
731
/// Unregister a listener of extension node changes.
733
/// <param name="path">
734
/// Path of the node.
736
/// <param name="handler">
737
/// A handler method.
740
/// This method unregisters a delegate from the node change event of a path.
742
public static void RemoveExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
744
AddinEngine.CheckInitialized ();
745
AddinEngine.RemoveExtensionNodeHandler (path, handler);
749
/// Register a listener of extension node changes.
751
/// <param name="instanceType">
752
/// Type defining the extension point
754
/// <param name="handler">
755
/// A handler method.
758
/// Hosts can call this method to be subscribed to an extension change
759
/// event for a specific type extension point. The event will be fired once for every
760
/// individual node change. The event arguments include the change type
761
/// (Add or Remove) and the extension node added or removed.
763
/// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
765
public static void AddExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
767
AddinEngine.CheckInitialized ();
768
AddinEngine.AddExtensionNodeHandler (instanceType, handler);
772
/// Unregister a listener of extension node changes.
774
/// <param name="instanceType">
775
/// Type defining the extension point
777
/// <param name="handler">
778
/// A handler method.
780
public static void RemoveExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
782
AddinEngine.CheckInitialized ();
783
AddinEngine.RemoveExtensionNodeHandler (instanceType, handler);
787
/// Add-in loading error event.
790
/// This event is fired when there is an error when loading the extension
791
/// of an add-in, or any other kind of error that may happen when querying extension points.
793
public static event AddinErrorEventHandler AddinLoadError {
794
add { AddinEngine.AddinLoadError += value; }
795
remove { AddinEngine.AddinLoadError -= value; }
799
/// Add-in loaded event.
802
/// Fired after loading an add-in in memory.
804
public static event AddinEventHandler AddinLoaded {
805
add { AddinEngine.AddinLoaded += value; }
806
remove { AddinEngine.AddinLoaded -= value; }
810
/// Add-in unload event.
813
/// Fired when an add-in is unloaded from memory. It may happen an add-in is disabled or uninstalled.
815
public static event AddinEventHandler AddinUnloaded {
816
add { AddinEngine.AddinUnloaded += value; }
817
remove { AddinEngine.AddinUnloaded -= value; }
820
internal static bool CheckAssembliesLoaded (HashSet<string> files)
822
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) {
823
if (asm is System.Reflection.Emit.AssemblyBuilder)
827
if (!Uri.TryCreate (asm.CodeBase, UriKind.Absolute, out u))
829
string asmFile = u.LocalPath;
830
if (files.Contains (Path.GetFullPath (asmFile)))