//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Drawing { using System; using System.Configuration; using System.Drawing.Configuration; using System.IO; using System.Reflection; /// /// Provides methods to select from multiple bitmaps depending on a "bitmapSuffix" config setting. /// internal static class BitmapSelector { /// /// Gets the bitmap ID suffix defined in the application configuration, or string.Empty if /// the suffix is not specified. Internal for unit tests /// /// /// For performance, the suffix is cached in a static variable so it only has to be read /// once per appdomain. /// private static string _suffix; internal static string Suffix { get { if (_suffix == null) { _suffix = string.Empty; var section = ConfigurationManager.GetSection("system.drawing") as SystemDrawingSection; if (section != null) { var value = section.BitmapSuffix; if (value != null && value is string) { _suffix = (string)value; } } } return _suffix; } set { // So unit tests can clear the cached suffix _suffix = value; } } /// /// Appends the current suffix to . The suffix is appended /// before the existing extension (if any). Internal for unit tests. /// /// /// The new path with the suffix included. If there is no suffix defined or there are /// invalid characters in the original path, the original path is returned. /// internal static string AppendSuffix(string filePath) { try { return Path.ChangeExtension(filePath, Suffix + Path.GetExtension(filePath)); } catch (ArgumentException) { // there are invalid characters in the path return filePath; } } /// /// Returns with the current suffix appended (before the /// existing extension) if the resulting file path exists; otherwise the original path is /// returned. /// public static string GetFileName(string originalPath) { if (Suffix == string.Empty) return originalPath; string newPath = AppendSuffix(originalPath); return File.Exists(newPath) ? newPath : originalPath; } // Calls assembly.GetManifestResourceStream in a try/catch and returns null if not found private static Stream GetResourceStreamHelper(Assembly assembly, Type type, string name) { Stream stream = null; try { stream = assembly.GetManifestResourceStream(type, name); } catch (FileNotFoundException) { } return stream; } private static bool DoesAssemblyHaveCustomAttribute(Assembly assembly, string typeName) { return DoesAssemblyHaveCustomAttribute(assembly, assembly.GetType(typeName)); } private static bool DoesAssemblyHaveCustomAttribute(Assembly assembly, Type attrType) { if (attrType != null) { var attr = assembly.GetCustomAttributes(attrType, false); if (attr.Length > 0) { return true; } } return false; } // internal for unit tests internal static bool SatelliteAssemblyOptIn(Assembly assembly) { // Try 4.5 public attribute type first if (DoesAssemblyHaveCustomAttribute(assembly, typeof(BitmapSuffixInSatelliteAssemblyAttribute))) { return true; } // Also load attribute type by name for dlls compiled against older frameworks return DoesAssemblyHaveCustomAttribute(assembly, "System.Drawing.BitmapSuffixInSatelliteAssemblyAttribute"); } // internal for unit tests internal static bool SameAssemblyOptIn(Assembly assembly) { // Try 4.5 public attribute type first if (DoesAssemblyHaveCustomAttribute(assembly, typeof(BitmapSuffixInSameAssemblyAttribute))) { return true; } // Also load attribute type by name for dlls compiled against older frameworks return DoesAssemblyHaveCustomAttribute(assembly, "System.Drawing.BitmapSuffixInSameAssemblyAttribute"); } /// /// Returns a resource stream loaded from the appropriate location according to the current /// suffix. /// /// The assembly from which the stream is loaded /// The type whose namespace is used to scope the manifest resource name /// The name of the manifest resource being requested /// /// The manifest resource stream corresponding to with the /// current suffix applied; or if that is not found, the stream corresponding to . /// public static Stream GetResourceStream(Assembly assembly, Type type, string originalName) { if (Suffix != string.Empty) { try { // Resource with suffix has highest priority if (SameAssemblyOptIn(assembly)) { string newName = AppendSuffix(originalName); Stream stream = GetResourceStreamHelper(assembly, type, newName); if (stream != null) { return stream; } } } catch { // Ignore failures and continue to try other options } try { // Satellite assembly has second priority, using the original name if (SatelliteAssemblyOptIn(assembly)) { AssemblyName assemblyName = assembly.GetName(); assemblyName.Name += Suffix; assemblyName.ProcessorArchitecture = ProcessorArchitecture.None; Assembly satellite = Assembly.Load(assemblyName); if (satellite != null) { Stream stream = GetResourceStreamHelper(satellite, type, originalName); if (stream != null) { return stream; } } } } catch { // Ignore failures and continue to try other options } } // Otherwise fall back to specified assembly and original name requested return assembly.GetManifestResourceStream(type, originalName); } /// /// Returns a resource stream loaded from the appropriate location according to the current /// suffix. /// /// The type from whose assembly the stream is loaded and whose namespace is used to scope the resource name /// The name of the manifest resource being requested /// /// The manifest resource stream corresponding to with the /// current suffix applied; or if that is not found, the stream corresponding to . /// public static Stream GetResourceStream(Type type, string originalName) { return GetResourceStream(type.Module.Assembly, type, originalName); } /// /// Returns an Icon created from a resource stream loaded from the appropriate location according to the current /// suffix. /// /// The type from whose assembly the stream is loaded and whose namespace is used to scope the resource name /// The name of the manifest resource being requested /// /// The icon created from a manifest resource stream corresponding to with the /// current suffix applied; or if that is not found, the stream corresponding to . /// public static Icon CreateIcon(Type type, string originalName) { return new Icon(GetResourceStream(type, originalName)); } /// /// Returns an Bitmap created from a resource stream loaded from the appropriate location according to the current /// suffix. /// /// The type from whose assembly the stream is loaded and whose namespace is used to scope the resource name /// The name of the manifest resource being requested /// /// The bitmap created from a manifest resource stream corresponding to with the /// current suffix applied; or if that is not found, the stream corresponding to . /// public static Bitmap CreateBitmap(Type type, string originalName) { return new Bitmap(GetResourceStream(type, originalName)); } } }