Completing the rest of the previous commit, forgot that it changed Core as well.
[castle.git] / AspectSharp / AspectSharp.Lang / GacHelper.cs
blobfcfc1cadc34d3711ad7f9d526cc826f54f3ed44c
1 #if DOTNET2
3 #region Modification Notes
5 // August 12 2005
6 // Modified by Jose Luis Barreda G. (joseluiseco 'at' hotmail 'dot' com)
7 // Changed name 'AssemblyCache' for 'GacHelper'
8 // Added 'FindAssembly' method and removed anything not needed by this method.
9 // Based on code from http://www.codeproject.com/csharp/GacApi.asp
10 // Used to simulate 'Assembly.LoadWithPartialName' (obsolete since .NET 2.0 Beta)
12 #endregion
14 #region Original notes
15 // Source: Microsoft KB Article KB317540
18 SUMMARY
19 The native code application programming interfaces (APIs) that allow you to interact with the Global Assembly Cache (GAC) are not documented
20 in the .NET Framework Software Development Kit (SDK) documentation.
22 MORE INFORMATION
23 CAUTION: Do not use these APIs in your application to perform assembly binds or to test for the presence of assemblies or other run time,
24 development, or design-time operations. Only administrative tools and setup programs must use these APIs. If you use the GAC, this directly
25 exposes your application to assembly binding fragility or may cause your application to work improperly on future versions of the .NET
26 Framework.
28 The GAC stores assemblies that are shared across all applications on a computer. The actual storage location and structure of the GAC is
29 not documented and is subject to change in future versions of the .NET Framework and the Microsoft Windows operating system.
31 The only supported method to access assemblies in the GAC is through the APIs that are documented in this article.
33 Most applications do not have to use these APIs because the assembly binding is performed automatically by the common language runtime.
34 Only custom setup programs or management tools must use these APIs. Microsoft Windows Installer has native support for installing assemblies
35 to the GAC.
37 For more information about assemblies and the GAC, see the .NET Framework SDK.
39 Use the GAC API in the following scenarios:
40 When you install nativeName assembly to the GAC.
41 When you remove nativeName assembly from the GAC.
42 When you export nativeName assembly from the GAC.
43 When you enumerate assemblies that are available in the GAC.
44 NOTE: CoInitialize(Ex) must be called before you use any of the functions and interfaces that are described in this specification.
46 #endregion
48 #region Using directives
50 using System;
51 using System.Collections.Generic;
52 using System.Text;
53 using System.Reflection;
54 using System.Runtime.InteropServices;
55 using System.Globalization;
57 #endregion
59 namespace AspectSharp.Lang
61 /// <summary>
62 /// Provides a method to find nativeName assembly in the GAC by it's simple name.
63 /// </summary>
64 internal static class GacHelper
67 #region FindAssembly
69 /// <summary>
70 ///
71 /// </summary>
72 /// <param name="assemblyName"></param>
73 /// <returns></returns>
74 public static Assembly FindAssembly(string assemblyName)
76 IAssemblyEnum assemblyEnum = GacHelper.CreateGACEnum();
77 IAssemblyName nativeName;
79 List<AssemblyName> matches = new List<AssemblyName>();
81 while(GacHelper.GetNextAssembly(assemblyEnum, out nativeName) == 0)
83 string nameString = GacHelper.GetName(nativeName);
85 if(StringComparer.InvariantCultureIgnoreCase.Compare(nameString, assemblyName) == 0)
87 AssemblyName name = GacHelper.GetAssemblyName(nativeName);
88 matches.Add(name);
92 AssemblyName last = null;
94 for(int i = 0; i < matches.Count; i++)
96 AssemblyName current = matches[i];
98 if(last != null)
100 if(last.Version.Major <= current.Version.Major)
102 if(last.Version.Major < current.Version.Major)
104 last = current;
106 else
108 if(last.Version.Minor < current.Version.Minor)
110 last = current;
115 else
117 last = current;
121 if(last != null)
123 return Assembly.Load(last);
125 else
127 return null;
131 #endregion
133 #region GetAssemblyName
135 private static AssemblyName GetAssemblyName(IAssemblyName nameRef)
137 AssemblyName name = new AssemblyName();
138 name.Name = GacHelper.GetName(nameRef);
139 name.Version = GacHelper.GetVersion(nameRef);
140 name.CultureInfo = GacHelper.GetCulture(nameRef);
141 name.SetPublicKeyToken(GacHelper.GetPublicKeyToken(nameRef));
143 return name;
146 #endregion
148 #region GetName
150 private static string GetName(IAssemblyName name)
152 uint bufferSize = 255;
153 StringBuilder buffer = new StringBuilder((int)bufferSize);
154 name.GetName(ref bufferSize, buffer);
156 return buffer.ToString();
159 #endregion
161 #region GetVersion
163 private static Version GetVersion(IAssemblyName name)
165 uint majorOut;
166 uint minorOut;
167 name.GetVersion(out majorOut, out minorOut);
169 int major = (int)majorOut >> 16;
170 int minor = (int)majorOut & 0xFFFF;
171 int build = (int)minorOut >> 16;
172 int revision = (int)minorOut & 0xFFFF;
174 if(major < 0)
176 major = major * -1;
179 if(minor < 0)
181 minor = minor * -1;
184 if(build < 0)
186 build = build * -1;
189 if(revision < 0)
191 revision = revision * -1;
194 return new Version(major, minor, build, revision);
197 #endregion
199 #region GetCulture
201 private static CultureInfo GetCulture(IAssemblyName name)
203 uint bufferSize = 255;
204 IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize);
205 name.GetProperty(ASM_NAME.ASM_NAME_CULTURE, buffer, ref bufferSize);
206 string result = Marshal.PtrToStringAuto(buffer);
207 Marshal.FreeHGlobal(buffer);
209 return new CultureInfo(result);
212 #endregion
214 #region GetPublicKeyToken
216 private static byte[] GetPublicKeyToken(IAssemblyName name)
218 byte[] result = new byte[8];
219 uint bufferSize = 8;
220 IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize);
221 name.GetProperty(ASM_NAME.ASM_NAME_PUBLIC_KEY_TOKEN, buffer, ref bufferSize);
222 for(int i = 0; i < 8; i++)
223 result[i] = Marshal.ReadByte(buffer, i);
224 Marshal.FreeHGlobal(buffer);
225 return result;
228 #endregion
230 #region CreateGACEnum
232 private static IAssemblyEnum CreateGACEnum()
234 IAssemblyEnum ae;
236 GacHelper.CreateAssemblyEnum(out ae, (IntPtr)0, null, ASM_CACHE_FLAGS.ASM_CACHE_GAC, (IntPtr)0);
238 return ae;
241 #endregion
243 #region GetNextAssembly
245 /// <summary>
246 /// Get the next assembly name in the current enumerator or fail
247 /// </summary>
248 /// <param name="enumerator"></param>
249 /// <param name="name"></param>
250 /// <returns>0 if the enumeration is not at its end</returns>
251 private static int GetNextAssembly(IAssemblyEnum enumerator, out IAssemblyName name)
253 return enumerator.GetNextAssembly((IntPtr)0, out name, 0);
256 #endregion
258 #region External methods
260 /// <summary>
261 /// To obtain nativeName instance of the CreateAssemblyEnum API, call the CreateAssemblyNameObject API.
262 /// </summary>
263 /// <param name="pEnum">Pointer to a memory location that contains the IAssemblyEnum pointer.</param>
264 /// <param name="pUnkReserved">Must be null.</param>
265 /// <param name="pName">An assembly name that is used to filter the enumeration. Can be null to enumerate all assemblies in the GAC.</param>
266 /// <param name="dwFlags">Exactly one bit from the ASM_CACHE_FLAGS enumeration.</param>
267 /// <param name="pvReserved">Must be NULL.</param>
268 [DllImport("fusion.dll", SetLastError = true, PreserveSig = false)]
269 private static extern void CreateAssemblyEnum(
270 out IAssemblyEnum pEnum,
271 IntPtr pUnkReserved,
272 IAssemblyName pName,
273 ASM_CACHE_FLAGS dwFlags,
274 IntPtr pvReserved);
276 #endregion
280 #region Flags
282 #region ASM_DISPLAY_FLAGS
284 /// <summary>
285 /// <see cref="IAssemblyName.GetDisplayName"/>
286 /// </summary>
287 [Flags]
288 internal enum ASM_DISPLAY_FLAGS
290 VERSION = 0x1,
291 CULTURE = 0x2,
292 PUBLIC_KEY_TOKEN = 0x4,
293 PUBLIC_KEY = 0x8,
294 CUSTOM = 0x10,
295 PROCESSORARCHITECTURE = 0x20,
296 LANGUAGEID = 0x40
299 #endregion
301 #region ASM_CMP_FLAGS
303 [Flags]
304 internal enum ASM_CMP_FLAGS
306 NAME = 0x1,
307 MAJOR_VERSION = 0x2,
308 MINOR_VERSION = 0x4,
309 BUILD_NUMBER = 0x8,
310 REVISION_NUMBER = 0x10,
311 PUBLIC_KEY_TOKEN = 0x20,
312 CULTURE = 0x40,
313 CUSTOM = 0x80,
314 ALL = NAME | MAJOR_VERSION | MINOR_VERSION |
315 REVISION_NUMBER | BUILD_NUMBER |
316 PUBLIC_KEY_TOKEN | CULTURE | CUSTOM,
317 DEFAULT = 0x100
320 #endregion
322 #region ASM_NAME
324 /// <summary>
325 /// The ASM_NAME enumeration property ID describes the valid names of the name-value pairs in nativeName assembly name.
326 /// See the .NET Framework SDK for a description of these properties.
327 /// </summary>
328 internal enum ASM_NAME
330 ASM_NAME_PUBLIC_KEY = 0,
331 ASM_NAME_PUBLIC_KEY_TOKEN,
332 ASM_NAME_HASH_VALUE,
333 ASM_NAME_NAME,
334 ASM_NAME_MAJOR_VERSION,
335 ASM_NAME_MINOR_VERSION,
336 ASM_NAME_BUILD_NUMBER,
337 ASM_NAME_REVISION_NUMBER,
338 ASM_NAME_CULTURE,
339 ASM_NAME_PROCESSOR_ID_ARRAY,
340 ASM_NAME_OSINFO_ARRAY,
341 ASM_NAME_HASH_ALGID,
342 ASM_NAME_ALIAS,
343 ASM_NAME_CODEBASE_URL,
344 ASM_NAME_CODEBASE_LASTMOD,
345 ASM_NAME_NULL_PUBLIC_KEY,
346 ASM_NAME_NULL_PUBLIC_KEY_TOKEN,
347 ASM_NAME_CUSTOM,
348 ASM_NAME_NULL_CUSTOM,
349 ASM_NAME_MVID,
350 ASM_NAME_MAX_PARAMS
353 #endregion
355 #region ASM_CACHE_FLAGS
357 /// <summary>
358 /// The ASM_CACHE_FLAGS enumeration contains the following values:
359 /// ASM_CACHE_ZAP - Enumerates the cache of precompiled assemblies by using Ngen.exe.
360 /// ASM_CACHE_GAC - Enumerates the GAC.
361 /// ASM_CACHE_DOWNLOAD - Enumerates the assemblies that have been downloaded on-demand or that have been shadow-copied.
362 /// </summary>
363 [Flags]
364 internal enum ASM_CACHE_FLAGS
366 ASM_CACHE_ZAP = 0x1,
367 ASM_CACHE_GAC = 0x2,
368 ASM_CACHE_DOWNLOAD = 0x4
371 #endregion
373 #endregion
375 #region IAssemblyName interface
377 /// <summary>
378 /// The IAssemblyName interface represents nativeName assembly name. An assembly name includes a predetermined set of name-value pairs.
379 /// The assembly name is described in detail in the .NET Framework SDK.
380 /// </summary>
381 [ComImport, Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E"),
382 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
383 internal interface IAssemblyName
385 /// <summary>
386 /// The IAssemblyName::SetProperty method adds a name-value pair to the assembly name, or, if a name-value pair
387 /// with the same name already exists, modifies or deletes the value of a name-value pair.
388 /// </summary>
389 /// <param name="PropertyId">The ID that represents the name part of the name-value pair that is to be
390 /// added or to be modified. Valid property IDs are defined in the ASM_NAME enumeration.</param>
391 /// <param name="pvProperty">A pointer to a buffer that contains the value of the property.</param>
392 /// <param name="cbProperty">The length of the pvProperty buffer in bytes. If cbProperty is zero, the name-value pair
393 /// is removed from the assembly name.</param>
394 /// <returns></returns>
395 [PreserveSig]
396 int SetProperty(
397 ASM_NAME PropertyId,
398 IntPtr pvProperty,
399 uint cbProperty);
401 /// <summary>
402 /// The IAssemblyName::GetProperty method retrieves the value of a name-value pair in the assembly name that specifies the name.
403 /// </summary>
404 /// <param name="PropertyId">The ID that represents the name of the name-value pair whose value is to be retrieved.
405 /// Specified property IDs are defined in the ASM_NAME enumeration.</param>
406 /// <param name="pvProperty">A pointer to a buffer that is to contain the value of the property.</param>
407 /// <param name="pcbProperty">The length of the pvProperty buffer, in bytes.</param>
408 /// <returns></returns>
409 [PreserveSig]
410 int GetProperty(
411 ASM_NAME PropertyId,
412 IntPtr pvProperty,
413 ref uint pcbProperty);
415 /// <summary>
416 /// The IAssemblyName::Finalize method freezes nativeName assembly name. Additional calls to IAssemblyName::SetProperty are
417 /// unsuccessful after this method has been called.
418 /// </summary>
419 /// <returns></returns>
420 [PreserveSig]
421 int Finalize();
423 /// <summary>
424 /// The IAssemblyName::GetDisplayName method returns a string representation of the assembly name.
425 /// </summary>
426 /// <param name="szDisplayName">A pointer to a buffer that is to contain the display name. The display name is returned in Unicode.</param>
427 /// <param name="pccDisplayName">The size of the buffer in characters (on input). The length of the returned display name (on return).</param>
428 /// <param name="dwDisplayFlags">One or more of the bits defined in the ASM_DISPLAY_FLAGS enumeration:
429 /// *_VERSION - Includes the version number as part of the display name.
430 /// *_CULTURE - Includes the culture.
431 /// *_PUBLIC_KEY_TOKEN - Includes the public key token.
432 /// *_PUBLIC_KEY - Includes the public key.
433 /// *_CUSTOM - Includes the custom part of the assembly name.
434 /// *_PROCESSORARCHITECTURE - Includes the processor architecture.
435 /// *_LANGUAGEID - Includes the language ID.</param>
436 /// <returns></returns>
437 /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp</remarks>
438 [PreserveSig]
439 int GetDisplayName(
440 [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szDisplayName,
441 ref uint pccDisplayName,
442 ASM_DISPLAY_FLAGS dwDisplayFlags);
444 /// <summary>
445 /// Undocumented
446 /// </summary>
447 /// <param name="refIID"></param>
448 /// <param name="pUnkSink"></param>
449 /// <param name="pUnkContext"></param>
450 /// <param name="szCodeBase"></param>
451 /// <param name="llFlags"></param>
452 /// <param name="pvReserved"></param>
453 /// <param name="cbReserved"></param>
454 /// <param name="ppv"></param>
455 /// <returns></returns>
456 [PreserveSig]
457 int BindToObject(
458 ref Guid refIID,
459 [MarshalAs(UnmanagedType.IUnknown)] object pUnkSink,
460 [MarshalAs(UnmanagedType.IUnknown)] object pUnkContext,
461 [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase,
462 long llFlags,
463 IntPtr pvReserved,
464 uint cbReserved,
465 out IntPtr ppv);
467 /// <summary>
468 /// The IAssemblyName::GetName method returns the name part of the assembly name.
469 /// </summary>
470 /// <param name="lpcwBuffer">Size of the pwszName buffer (on input). Length of the name (on return).</param>
471 /// <param name="pwzName">Pointer to the buffer that is to contain the name part of the assembly name.</param>
472 /// <returns></returns>
473 /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp</remarks>
474 [PreserveSig]
475 int GetName(
476 ref uint lpcwBuffer,
477 [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwzName);
479 /// <summary>
480 /// The IAssemblyName::GetVersion method returns the version part of the assembly name.
481 /// </summary>
482 /// <param name="pdwVersionHi">Pointer to a DWORD that contains the upper 32 bits of the version number.</param>
483 /// <param name="pdwVersionLow">Pointer to a DWORD that contain the lower 32 bits of the version number.</param>
484 /// <returns></returns>
485 [PreserveSig]
486 int GetVersion(
487 out uint pdwVersionHi,
488 out uint pdwVersionLow);
490 /// <summary>
491 /// The IAssemblyName::IsEqual method compares the assembly name to another assembly names.
492 /// </summary>
493 /// <param name="pName">The assembly name to compare to.</param>
494 /// <param name="dwCmpFlags">Indicates which part of the assembly name to use in the comparison.
495 /// Values are one or more of the bits defined in the ASM_CMP_FLAGS enumeration.</param>
496 /// <returns></returns>
497 [PreserveSig]
498 int IsEqual(
499 IAssemblyName pName,
500 ASM_CMP_FLAGS dwCmpFlags);
502 /// <summary>
503 /// The IAssemblyName::Clone method creates a copy of nativeName assembly name.
504 /// </summary>
505 /// <param name="pName"></param>
506 /// <returns></returns>
507 [PreserveSig]
508 int Clone(
509 out IAssemblyName pName);
512 #endregion
514 #region IAssemblyEnum interface
516 /// <summary>
517 /// The IAssemblyEnum interface enumerates the assemblies in the GAC.
518 /// </summary>
519 [ComImport, Guid("21b8916c-f28e-11d2-a473-00c04f8ef448"),
520 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
521 internal interface IAssemblyEnum
523 /// <summary>
524 /// The IAssemblyEnum::GetNextAssembly method enumerates the assemblies in the GAC.
525 /// </summary>
526 /// <param name="pvReserved">Must be null.</param>
527 /// <param name="ppName">Pointer to a memory location that is to receive the interface pointer to the assembly
528 /// name of the next assembly that is enumerated.</param>
529 /// <param name="dwFlags">Must be zero.</param>
530 /// <returns></returns>
531 [PreserveSig()]
532 int GetNextAssembly(
533 IntPtr pvReserved,
534 out IAssemblyName ppName,
535 uint dwFlags);
537 /// <summary>
538 /// Undocumented. Best guess: reset the enumeration to the first assembly.
539 /// </summary>
540 /// <returns></returns>
541 [PreserveSig()]
542 int Reset();
544 /// <summary>
545 /// Undocumented. Create a copy of the assembly enum that is independently enumerable.
546 /// </summary>
547 /// <param name="ppEnum"></param>
548 /// <returns></returns>
549 [PreserveSig()]
550 int Clone(
551 out IAssemblyEnum ppEnum);
554 #endregion
557 #endif