1 //
2 // AddinManager.cs
3 //
4 // Author:
5 //   Lluis Sanchez Gual
6 //
7 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27 //
28 
29 using System;
30 using System.IO;
31 using System.Reflection;
32 using System.Collections;
33 using System.Collections.Generic;
34 
35 using Mono.Addins.Localization;
36 
37 namespace Mono.Addins
38 {
39 	/// <summary>
40 	/// Provides access to add-in and extension model management operations.
41 	/// </summary>
42 	public class AddinManager
43 	{
44 		static AddinEngine sessionService;
45 
AddinManager()46 		private AddinManager ()
47 		{
48 		}
49 
50 		/// <summary>
51 		/// Initializes the add-in engine.
52 		/// </summary>
53 		/// <remarks>
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.
56 		/// </remarks>
Initialize()57 		public static void Initialize ()
58 		{
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);
63 		}
64 
65 		/// <summary>
66 		/// Initializes the add-in engine.
67 		/// </summary>
68 		/// <param name="configDir">
69 		/// Location of the add-in registry.
70 		/// </param>
71 		/// <remarks>
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.
76 		///
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
81 		/// brackets)
82 		/// </remarks>
Initialize(string configDir)83 		public static void Initialize (string configDir)
84 		{
85 			Assembly asm = Assembly.GetEntryAssembly ();
86 			if (asm == null) asm = Assembly.GetCallingAssembly ();
87 			AddinEngine.Initialize (asm, configDir, null, null);
88 		}
89 
90 		/// <summary>
91 		/// Initializes the add-in engine.
92 		/// </summary>
93 		/// <param name='configDir'>
94 		/// Location of the add-in registry.
95 		/// </param>
96 		/// <param name='addinsDir'>
97 		/// Add-ins directory. If the path is relative, it is considered to be relative
98 		/// to the configDir directory.
99 		/// </param>
100 		/// <remarks>
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.
105 		///
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
110 		/// brackets)
111 		/// </remarks>
Initialize(string configDir, string addinsDir)112 		public static void Initialize (string configDir, string addinsDir)
113 		{
114 			Assembly asm = Assembly.GetEntryAssembly ();
115 			if (asm == null) asm = Assembly.GetCallingAssembly ();
116 			AddinEngine.Initialize (asm, configDir, addinsDir, null);
117 		}
118 
119 		/// <summary>
120 		/// Initializes the add-in engine.
121 		/// </summary>
122 		/// <param name='configDir'>
123 		/// Location of the add-in registry.
124 		/// </param>
125 		/// <param name='addinsDir'>
126 		/// Add-ins directory. If the path is relative, it is considered to be relative
127 		/// to the configDir directory.
128 		/// </param>
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.
132 		/// </param>
133 		/// <remarks>
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.
139 		///
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
144 		/// brackets)
145 		/// </remarks>
Initialize(string configDir, string addinsDir, string databaseDir)146 		public static void Initialize (string configDir, string addinsDir, string databaseDir)
147 		{
148 			Assembly asm = Assembly.GetEntryAssembly ();
149 			if (asm == null) asm = Assembly.GetCallingAssembly ();
150 			AddinEngine.Initialize (asm, configDir, addinsDir, databaseDir);
151 		}
152 
153 		/// <summary>
154 		/// Finalizes an add-in engine.
155 		/// </summary>
Shutdown()156 		public static void Shutdown ()
157 		{
158 			AddinEngine.Shutdown ();
159 		}
160 
161 		/// <summary>
162 		/// Sets the default localizer to be used for this add-in engine
163 		/// </summary>
164 		/// <param name="localizer">
165 		/// The add-in localizer
166 		/// </param>
InitializeDefaultLocalizer(IAddinLocalizer localizer)167 		public static void InitializeDefaultLocalizer (IAddinLocalizer localizer)
168 		{
169 			AddinEngine.InitializeDefaultLocalizer (localizer);
170 		}
171 
172 		internal static string StartupDirectory {
173 			get { return AddinEngine.StartupDirectory; }
174 		}
175 
176 		/// <summary>
177 		/// Gets whether the add-in engine has been initialized.
178 		/// </summary>
179 		public static bool IsInitialized {
180 			get { return AddinEngine.IsInitialized; }
181 		}
182 
183 		/// <summary>
184 		/// Gets the default add-in installer
185 		/// </summary>
186 		/// <remarks>
187 		/// The default installer is used by the CheckInstalled method to request
188 		/// the installation of missing add-ins.
189 		/// </remarks>
190 		public static IAddinInstaller DefaultInstaller {
191 			get { return AddinEngine.DefaultInstaller; }
192 			set { AddinEngine.DefaultInstaller = value; }
193 		}
194 
195 		/// <summary>
196 		/// Gets the default localizer for this add-in engine
197 		/// </summary>
198 		public static AddinLocalizer DefaultLocalizer {
199 			get {
200 				return AddinEngine.DefaultLocalizer;
201 			}
202 		}
203 
204 		/// <summary>
205 		/// Gets the localizer for the add-in that is invoking this property
206 		/// </summary>
207 		public static AddinLocalizer CurrentLocalizer {
208 			get {
209 				AddinEngine.CheckInitialized ();
210 				RuntimeAddin addin = AddinEngine.GetAddinForAssembly (Assembly.GetCallingAssembly ());
211 				if (addin != null)
212 					return addin.Localizer;
213 				else
214 					return AddinEngine.DefaultLocalizer;
215 			}
216 		}
217 
218 		/// <summary>
219 		/// Gets a reference to the RuntimeAddin object for the add-in that is invoking this property
220 		/// </summary>
221 		public static RuntimeAddin CurrentAddin {
222 			get {
223 				AddinEngine.CheckInitialized ();
224 				return AddinEngine.GetAddinForAssembly (Assembly.GetCallingAssembly ());
225 			}
226 		}
227 
228 		/// <summary>
229 		/// Gets the default add-in engine
230 		/// </summary>
231 		public static AddinEngine AddinEngine {
232 			get {
233 				if (sessionService == null)
234 					sessionService = new AddinEngine();
235 
236 				return sessionService;
237 			}
238 		}
239 
240 		/// <summary>
241 		/// Gets the add-in registry bound to the default add-in engine
242 		/// </summary>
243 		public static AddinRegistry Registry {
244 			get {
245 				return AddinEngine.Registry;
246 			}
247 		}
248 
249 		/// <summary>
250 		/// Checks if the provided add-ins are installed, and requests the installation of those
251 		/// which aren't.
252 		/// </summary>
253 		/// <param name="message">
254 		/// Message to show to the user when new add-ins have to be installed.
255 		/// </param>
256 		/// <param name="addinIds">
257 		/// List of IDs of the add-ins to be checked.
258 		/// </param>
259 		/// <remarks>
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.
265 		/// </remarks>
CheckInstalled(string message, params string[] addinIds)266 		public static void CheckInstalled (string message, params string[] addinIds)
267 		{
268 			AddinEngine.CheckInstalled (message, addinIds);
269 		}
270 
271 		/// <summary>
272 		/// Checks if an add-in has been loaded.
273 		/// </summary>
274 		/// <param name="id">
275 		/// Full identifier of the add-in.
276 		/// </param>
277 		/// <returns>
278 		/// True if the add-in is loaded.
279 		/// </returns>
IsAddinLoaded(string id)280 		public static bool IsAddinLoaded (string id)
281 		{
282 			return AddinEngine.IsAddinLoaded (id);
283 		}
284 
285 		/// <summary>
286 		/// Forces the loading of an add-in.
287 		/// </summary>
288 		/// <param name="statusMonitor">
289 		/// Status monitor to keep track of the loading process.
290 		/// </param>
291 		/// <param name="id">
292 		/// Full identifier of the add-in to load.
293 		/// </param>
294 		/// <remarks>
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 explicitly loaded using
298 		/// this method, since the add-in engine will load them on demand.
299 		/// </remarks>
LoadAddin(IProgressStatus statusMonitor, string id)300 		public static void LoadAddin (IProgressStatus statusMonitor, string id)
301 		{
302 			AddinEngine.LoadAddin (statusMonitor, id);
303 		}
304 
305 		/// <summary>
306 		/// Creates a new extension context.
307 		/// </summary>
308 		/// <returns>
309 		/// The new extension context.
310 		/// </returns>
311 		/// <remarks>
312 		/// Extension contexts can be used to query the extension model using particular condition values.
313 		/// </remarks>
CreateExtensionContext()314 		public static ExtensionContext CreateExtensionContext ()
315 		{
316 			return AddinEngine.CreateExtensionContext ();
317 		}
318 
319 		/// <summary>
320 		/// Returns the extension node in a path
321 		/// </summary>
322 		/// <param name="path">
323 		/// Location of the node.
324 		/// </param>
325 		/// <returns>
326 		/// The node, or null if not found.
327 		/// </returns>
GetExtensionNode(string path)328 		public static ExtensionNode GetExtensionNode (string path)
329 		{
330 			AddinEngine.CheckInitialized ();
331 			return AddinEngine.GetExtensionNode (path);
332 		}
333 
334 		/// <summary>
335 		/// Returns the extension node in a path
336 		/// </summary>
337 		/// <param name="path">
338 		/// Location of the node.
339 		/// </param>
340 		/// <returns>
341 		/// The node, or null if not found.
342 		/// </returns>
343 		public static T GetExtensionNode<T> (string path) where T:ExtensionNode
344 		{
345 			AddinEngine.CheckInitialized ();
346 			return AddinEngine.GetExtensionNode<T> (path);
347 		}
348 
349 		/// <summary>
350 		/// Gets extension nodes registered in a path.
351 		/// </summary>
352 		/// <param name="path">
353 		/// An extension path.>
354 		/// </param>
355 		/// <returns>
356 		/// All nodes registered in the provided path.
357 		/// </returns>
GetExtensionNodes(string path)358 		public static ExtensionNodeList GetExtensionNodes (string path)
359 		{
360 			AddinEngine.CheckInitialized ();
361 			return AddinEngine.GetExtensionNodes (path);
362 		}
363 
364 		/// <summary>
365 		/// Gets extension nodes registered in a path.
366 		/// </summary>
367 		/// <param name="path">
368 		/// An extension path.
369 		/// </param>
370 		/// <param name="expectedNodeType">
371 		/// Expected node type.
372 		/// </param>
373 		/// <returns>
374 		/// A list of nodes
375 		/// </returns>
376 		/// <remarks>
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.
380 		/// </remarks>
GetExtensionNodes(string path, Type expectedNodeType)381 		public static ExtensionNodeList GetExtensionNodes (string path, Type expectedNodeType)
382 		{
383 			AddinEngine.CheckInitialized ();
384 			return AddinEngine.GetExtensionNodes (path, expectedNodeType);
385 		}
386 
387 		/// <summary>
388 		/// Gets extension nodes registered in a path.
389 		/// </summary>
390 		/// <param name="path">
391 		/// An extension path.
392 		/// </param>
393 		/// <returns>
394 		/// A list of nodes
395 		/// </returns>
396 		/// <remarks>
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.
400 		/// </remarks>
401 		public static ExtensionNodeList<T> GetExtensionNodes<T> (string path) where T:ExtensionNode
402 		{
403 			AddinEngine.CheckInitialized ();
404 			return AddinEngine.GetExtensionNodes<T> (path);
405 		}
406 
407 		/// <summary>
408 		/// Gets extension nodes for a type extension point
409 		/// </summary>
410 		/// <param name="instanceType">
411 		/// Type defining the extension point
412 		/// </param>
413 		/// <returns>
414 		/// A list of nodes
415 		/// </returns>
416 		/// <remarks>
417 		/// This method returns all extension nodes bound to the provided type.
418 		/// </remarks>
GetExtensionNodes(Type instanceType)419 		public static ExtensionNodeList GetExtensionNodes (Type instanceType)
420 		{
421 			AddinEngine.CheckInitialized ();
422 			return AddinEngine.GetExtensionNodes (instanceType);
423 		}
424 
425 		/// <summary>
426 		/// Gets extension nodes for a type extension point
427 		/// </summary>
428 		/// <param name="instanceType">
429 		/// Type defining the extension point
430 		/// </param>
431 		/// <param name="expectedNodeType">
432 		/// Expected extension node type
433 		/// </param>
434 		/// <returns>
435 		/// A list of nodes
436 		/// </returns>
437 		/// <remarks>
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.
441 		/// </remarks>
GetExtensionNodes(Type instanceType, Type expectedNodeType)442 		public static ExtensionNodeList GetExtensionNodes (Type instanceType, Type expectedNodeType)
443 		{
444 			AddinEngine.CheckInitialized ();
445 			return AddinEngine.GetExtensionNodes (instanceType, expectedNodeType);
446 		}
447 
448 		/// <summary>
449 		/// Gets extension nodes for a type extension point
450 		/// </summary>
451 		/// <param name="instanceType">
452 		/// Type defining the extension point
453 		/// </param>
454 		/// <returns>
455 		/// A list of nodes
456 		/// </returns>
457 		/// <remarks>
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.
461 		/// </remarks>
462 		public static ExtensionNodeList<T> GetExtensionNodes<T> (Type instanceType) where T: ExtensionNode
463 		{
464 			AddinEngine.CheckInitialized ();
465 			return AddinEngine.GetExtensionNodes<T> (instanceType);
466 		}
467 
468 		/// <summary>
469 		/// Gets extension objects registered for a type extension point.
470 		/// </summary>
471 		/// <param name="instanceType">
472 		/// Type defining the extension point
473 		/// </param>
474 		/// <returns>
475 		/// A list of objects
476 		/// </returns>
GetExtensionObjects(Type instanceType)477 		public static object[] GetExtensionObjects (Type instanceType)
478 		{
479 			AddinEngine.CheckInitialized ();
480 			return AddinEngine.GetExtensionObjects (instanceType);
481 		}
482 
483 		/// <summary>
484 		/// Gets extension objects registered for a type extension point.
485 		/// </summary>
486 		/// <returns>
487 		/// A list of objects
488 		/// </returns>
489 		/// <remarks>
490 		/// The type argument of this generic method is the type that defines
491 		/// the extension point.
492 		/// </remarks>
GetExtensionObjects()493 		public static T[] GetExtensionObjects<T> ()
494 		{
495 			AddinEngine.CheckInitialized ();
496 			return AddinEngine.GetExtensionObjects<T> ();
497 		}
498 
499 		/// <summary>
500 		/// Gets extension objects registered for a type extension point.
501 		/// </summary>
502 		/// <param name="instanceType">
503 		/// Type defining the extension point
504 		/// </param>
505 		/// <param name="reuseCachedInstance">
506 		/// When set to True, it will return instances created in previous calls.
507 		/// </param>
508 		/// <returns>
509 		/// A list of extension objects.
510 		/// </returns>
GetExtensionObjects(Type instanceType, bool reuseCachedInstance)511 		public static object[] GetExtensionObjects (Type instanceType, bool reuseCachedInstance)
512 		{
513 			AddinEngine.CheckInitialized ();
514 			return AddinEngine.GetExtensionObjects (instanceType, reuseCachedInstance);
515 		}
516 
517 		/// <summary>
518 		/// Gets extension objects registered for a type extension point.
519 		/// </summary>
520 		/// <param name="reuseCachedInstance">
521 		/// When set to True, it will return instances created in previous calls.
522 		/// </param>
523 		/// <returns>
524 		/// A list of extension objects.
525 		/// </returns>
526 		/// <remarks>
527 		/// The type argument of this generic method is the type that defines
528 		/// the extension point.
529 		/// </remarks>
GetExtensionObjects(bool reuseCachedInstance)530 		public static T[] GetExtensionObjects<T> (bool reuseCachedInstance)
531 		{
532 			AddinEngine.CheckInitialized ();
533 			return AddinEngine.GetExtensionObjects<T> (reuseCachedInstance);
534 		}
535 
536 		/// <summary>
537 		/// Gets extension objects registered in a path
538 		/// </summary>
539 		/// <param name="path">
540 		/// An extension path.
541 		/// </param>
542 		/// <returns>
543 		/// An array of objects registered in the path.
544 		/// </returns>
545 		/// <remarks>
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.
550 		/// </remarks>
GetExtensionObjects(string path)551 		public static object[] GetExtensionObjects (string path)
552 		{
553 			AddinEngine.CheckInitialized ();
554 			return AddinEngine.GetExtensionObjects (path);
555 		}
556 
557 		/// <summary>
558 		/// Gets extension objects registered in a path.
559 		/// </summary>
560 		/// <param name="path">
561 		/// An extension path.
562 		/// </param>
563 		/// <param name="reuseCachedInstance">
564 		/// When set to True, it will return instances created in previous calls.
565 		/// </param>
566 		/// <returns>
567 		/// An array of objects registered in the path.
568 		/// </returns>
569 		/// <remarks>
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)
575 		/// </remarks>
GetExtensionObjects(string path, bool reuseCachedInstance)576 		public static object[] GetExtensionObjects (string path, bool reuseCachedInstance)
577 		{
578 			AddinEngine.CheckInitialized ();
579 			return AddinEngine.GetExtensionObjects (path, reuseCachedInstance);
580 		}
581 
582 		/// <summary>
583 		/// Gets extension objects registered in a path.
584 		/// </summary>
585 		/// <param name="path">
586 		/// An extension path.
587 		/// </param>
588 		/// <param name="arrayElementType">
589 		/// Type of the return array elements.
590 		/// </param>
591 		/// <returns>
592 		/// An array of objects registered in the path.
593 		/// </returns>
594 		/// <remarks>
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.
599 		///
600 		/// An InvalidOperationException exception is thrown if one of the found
601 		/// objects is not a subclass of the provided type.
602 		/// </remarks>
GetExtensionObjects(string path, Type arrayElementType)603 		public static object[] GetExtensionObjects (string path, Type arrayElementType)
604 		{
605 			AddinEngine.CheckInitialized ();
606 			return AddinEngine.GetExtensionObjects (path, arrayElementType);
607 		}
608 
609 		/// <summary>
610 		/// Gets extension objects registered in a path.
611 		/// </summary>
612 		/// <param name="path">
613 		/// An extension path.
614 		/// </param>
615 		/// <returns>
616 		/// An array of objects registered in the path.
617 		/// </returns>
618 		/// <remarks>
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.
623 		///
624 		/// An InvalidOperationException exception is thrown if one of the found
625 		/// objects is not a subclass of the provided type.
626 		/// </remarks>
GetExtensionObjects(string path)627 		public static T[] GetExtensionObjects<T> (string path)
628 		{
629 			AddinEngine.CheckInitialized ();
630 			return AddinEngine.GetExtensionObjects<T> (path);
631 		}
632 
633 		/// <summary>
634 		/// Gets extension objects registered in a path.
635 		/// </summary>
636 		/// <param name="path">
637 		/// An extension path.
638 		/// </param>
639 		/// <param name="arrayElementType">
640 		/// Type of the return array elements.
641 		/// </param>
642 		/// <param name="reuseCachedInstance">
643 		/// When set to True, it will return instances created in previous calls.
644 		/// </param>
645 		/// <returns>
646 		/// An array of objects registered in the path.
647 		/// </returns>
648 		/// <remarks>
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).
654 		///
655 		/// An InvalidOperationException exception is thrown if one of the found
656 		/// objects is not a subclass of the provided type.
657 		/// </remarks>
GetExtensionObjects(string path, Type arrayElementType, bool reuseCachedInstance)658 		public static object[] GetExtensionObjects (string path, Type arrayElementType, bool reuseCachedInstance)
659 		{
660 			AddinEngine.CheckInitialized ();
661 			return AddinEngine.GetExtensionObjects (path, arrayElementType, reuseCachedInstance);
662 		}
663 
664 		/// <summary>
665 		/// Gets extension objects registered in a path.
666 		/// </summary>
667 		/// <param name="path">
668 		/// An extension path.
669 		/// </param>
670 		/// <param name="reuseCachedInstance">
671 		/// When set to True, it will return instances created in previous calls.
672 		/// </param>
673 		/// <returns>
674 		/// An array of objects registered in the path.
675 		/// </returns>
676 		/// <remarks>
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).
682 		///
683 		/// An InvalidOperationException exception is thrown if one of the found
684 		/// objects is not a subclass of the provided type.
685 		/// </remarks>
GetExtensionObjects(string path, bool reuseCachedInstance)686 		public static T[] GetExtensionObjects<T> (string path, bool reuseCachedInstance)
687 		{
688 			AddinEngine.CheckInitialized ();
689 			return AddinEngine.GetExtensionObjects<T> (path, reuseCachedInstance);
690 		}
691 
692 		/// <summary>
693 		/// Extension change event.
694 		/// </summary>
695 		/// <remarks>
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.
701 		/// </remarks>
702 		public static event ExtensionEventHandler ExtensionChanged {
703 			add { AddinEngine.CheckInitialized(); AddinEngine.ExtensionChanged += value; }
704 			remove { AddinEngine.CheckInitialized(); AddinEngine.ExtensionChanged -= value; }
705 		}
706 
707 		/// <summary>
708 		/// Register a listener of extension node changes.
709 		/// </summary>
710 		/// <param name="path">
711 		/// Path of the node.
712 		/// </param>
713 		/// <param name="handler">
714 		/// A handler method.
715 		/// </param>
716 		/// <remarks>
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.
721 		///
722 		/// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
723 		/// </remarks>
AddExtensionNodeHandler(string path, ExtensionNodeEventHandler handler)724 		public static void AddExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
725 		{
726 			AddinEngine.CheckInitialized ();
727 			AddinEngine.AddExtensionNodeHandler (path, handler);
728 		}
729 
730 		/// <summary>
731 		/// Unregister a listener of extension node changes.
732 		/// </summary>
733 		/// <param name="path">
734 		/// Path of the node.
735 		/// </param>
736 		/// <param name="handler">
737 		/// A handler method.
738 		/// </param>
739 		/// <remarks>
740 		/// This method unregisters a delegate from the node change event of a path.
741 		/// </remarks>
RemoveExtensionNodeHandler(string path, ExtensionNodeEventHandler handler)742 		public static void RemoveExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
743 		{
744 			AddinEngine.CheckInitialized ();
745 			AddinEngine.RemoveExtensionNodeHandler (path, handler);
746 		}
747 
748 		/// <summary>
749 		/// Register a listener of extension node changes.
750 		/// </summary>
751 		/// <param name="instanceType">
752 		/// Type defining the extension point
753 		/// </param>
754 		/// <param name="handler">
755 		/// A handler method.
756 		/// </param>
757 		/// <remarks>
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.
762 		///
763 		/// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
764 		/// </remarks>
AddExtensionNodeHandler(Type instanceType, ExtensionNodeEventHandler handler)765 		public static void AddExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
766 		{
767 			AddinEngine.CheckInitialized ();
768 			AddinEngine.AddExtensionNodeHandler (instanceType, handler);
769 		}
770 
771 		/// <summary>
772 		/// Unregister a listener of extension node changes.
773 		/// </summary>
774 		/// <param name="instanceType">
775 		/// Type defining the extension point
776 		/// </param>
777 		/// <param name="handler">
778 		/// A handler method.
779 		/// </param>
RemoveExtensionNodeHandler(Type instanceType, ExtensionNodeEventHandler handler)780 		public static void RemoveExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
781 		{
782 			AddinEngine.CheckInitialized ();
783 			AddinEngine.RemoveExtensionNodeHandler (instanceType, handler);
784 		}
785 
786 		/// <summary>
787 		/// Add-in loading error event.
788 		/// </summary>
789 		/// <remarks>
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.
792 		/// </remarks>
793 		public static event AddinErrorEventHandler AddinLoadError {
794 			add { AddinEngine.AddinLoadError += value; }
795 			remove { AddinEngine.AddinLoadError -= value; }
796 		}
797 
798 		/// <summary>
799 		/// Add-in loaded event.
800 		/// </summary>
801 		/// <remarks>
802 		/// Fired after loading an add-in in memory.
803 		/// </remarks>
804 		public static event AddinEventHandler AddinLoaded {
805 			add { AddinEngine.AddinLoaded += value; }
806 			remove { AddinEngine.AddinLoaded -= value; }
807 		}
808 
809 		/// <summary>
810 		/// Add-in unload event.
811 		/// </summary>
812 		/// <remarks>
813 		/// Fired when an add-in is unloaded from memory. It may happen an add-in is disabled or uninstalled.
814 		/// </remarks>
815 		public static event AddinEventHandler AddinUnloaded {
816 			add { AddinEngine.AddinUnloaded += value; }
817 			remove { AddinEngine.AddinUnloaded -= value; }
818 		}
819 
CheckAssembliesLoaded(HashSet<string> files)820 		internal static bool CheckAssembliesLoaded (HashSet<string> files)
821 		{
822 			foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) {
823 				if (asm is System.Reflection.Emit.AssemblyBuilder)
824 					continue;
825 				try {
826 					Uri u;
827 					if (!Uri.TryCreate (asm.CodeBase, UriKind.Absolute, out u))
828 						continue;
829 					string asmFile = u.LocalPath;
830 					if (files.Contains (Path.GetFullPath (asmFile)))
831 						return true;
832 				} catch {
833 					// Ignore
834 				}
835 			}
836 			return false;
837 		}
838 	}
839 
840 }
841