Click here to Skip to main content
15,896,726 members
Articles / Desktop Programming / Win32

File Resource Management Library (.NET)

Rate me:
Please Sign up or sign in to vote.
4.82/5 (27 votes)
16 Sep 2009CPOL14 min read 134.5K   2.6K   113  
A .NET implementation of a file resource management, with complete support for VS_VERSIONINFO version resources.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace Vestris.ResourceLib
{
    /// <summary>
    /// Resource info manager.
    /// </summary>
    public class ResourceInfo : IEnumerable<Resource>, IDisposable
    {
        private IntPtr _hModule = IntPtr.Zero;
        private Dictionary<ResourceId, List<Resource>> _resources;
        private List<ResourceId> _resourceTypes = null;

        /// <summary>
        /// A dictionary of resources, the key is the resource type, eg. "REGISTRY" or "16" (version).
        /// </summary>
        public Dictionary<ResourceId, List<Resource>> Resources
        {
            get
            {
                return _resources;
            }
        }

        /// <summary>
        /// A shortcut for available resource types.
        /// </summary>
        public List<ResourceId> ResourceTypes
        {
            get
            {
                return _resourceTypes;
            }
        }

        /// <summary>
        /// A new resource info.
        /// </summary>
        public ResourceInfo()
        {

        }

        /// <summary>
        /// Unload the previously loaded module.
        /// </summary>
        public void Unload()
        {
            if (_hModule != IntPtr.Zero)
            {
                Kernel32.FreeLibrary(_hModule);
                _hModule = IntPtr.Zero;
            }
        }

        /// <summary>
        /// Load an executable or a DLL and read its resources.
        /// </summary>
        /// <param name="filename">Source filename.</param>
        public void Load(string filename)
        {
            Unload();

            _resourceTypes = new List<ResourceId>();
            _resources = new Dictionary<ResourceId, List<Resource>>();

            // load DLL
            _hModule = Kernel32.LoadLibraryEx(filename, IntPtr.Zero,
                Kernel32.DONT_RESOLVE_DLL_REFERENCES | Kernel32.LOAD_LIBRARY_AS_DATAFILE);

            if (IntPtr.Zero == _hModule)
                throw new Win32Exception(Marshal.GetLastWin32Error());

            // enumerate resource types
            // for each type, enumerate resource names
            // for each name, enumerate resource languages
            // for each resource language, enumerate actual resources
            if (!Kernel32.EnumResourceTypes(_hModule, EnumResourceTypesImpl, IntPtr.Zero))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        /// <summary>
        /// Enumerate resource types.
        /// </summary>
        /// <param name="hModule">Module handle.</param>
        /// <param name="lpszType">Resource type.</param>
        /// <param name="lParam">Additional parameter.</param>
        /// <returns>TRUE if successful.</returns>
        private bool EnumResourceTypesImpl(IntPtr hModule, IntPtr lpszType, IntPtr lParam)
        {
            ResourceId type = new ResourceId(lpszType);
            _resourceTypes.Add(type);

            // enumerate resource names
            if (!Kernel32.EnumResourceNames(hModule, lpszType, new Kernel32.EnumResourceNamesDelegate(EnumResourceNamesImpl), IntPtr.Zero))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return true;
        }

        /// <summary>
        /// Enumerate resource names within a resource by type
        /// </summary>
        /// <param name="hModule">Module handle.</param>
        /// <param name="lpszType">Resource type.</param>
        /// <param name="lpszName">Resource name.</param>
        /// <param name="lParam">Additional parameter.</param>
        /// <returns>TRUE if successful.</returns>
        private bool EnumResourceNamesImpl(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam)
        {
            if (!Kernel32.EnumResourceLanguages(hModule, lpszType, lpszName, new Kernel32.EnumResourceLanguagesDelegate(EnumResourceLanguages), IntPtr.Zero))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return true;
        }

        /// <summary>
        /// Create a resource of a given type.
        /// </summary>
        /// <param name="hModule">Module handle.</param>
        /// <param name="hResourceGlobal">Pointer to the resource in memory.</param>
        /// <param name="type">Resource type.</param>
        /// <param name="name">Resource name.</param>
        /// <param name="wIDLanguage">Language ID.</param>
        /// <param name="size">Size of resource.</param>
        /// <returns>A specialized or a generic resource.</returns>
        protected Resource CreateResource(
            IntPtr hModule, 
            IntPtr hResourceGlobal, 
            ResourceId type, 
            ResourceId name, 
            UInt16 wIDLanguage, 
            int size)
        {
            if (type.IsIntResource())
            {
                switch (type.ResourceType)
                {
                    case Kernel32.ResourceTypes.RT_VERSION:
                        return new VersionResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_GROUP_CURSOR:
                        return new CursorDirectoryResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_GROUP_ICON:
                        return new IconDirectoryResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_MANIFEST:
                        return new ManifestResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_BITMAP:
                        return new BitmapResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_MENU:
                        return new MenuResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_DIALOG:
                        return new DialogResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_STRING:
                        return new StringResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_FONTDIR:
                        return new FontDirectoryResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_FONT:
                        return new FontResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                    case Kernel32.ResourceTypes.RT_ACCELERATOR:
                        return new AcceleratorResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
                }
            }

            return new GenericResource(hModule, hResourceGlobal, type, name, wIDLanguage, size);
        }

        /// <summary>
        /// Enumerate resource languages within a resource by name
        /// </summary>
        /// <param name="hModule">Module handle.</param>
        /// <param name="lpszType">Resource type.</param>
        /// <param name="lpszName">Resource name.</param>
        /// <param name="wIDLanguage">Language ID.</param>
        /// <param name="lParam">Additional parameter.</param>
        /// <returns>TRUE if successful.</returns>
        private bool EnumResourceLanguages(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, UInt16 wIDLanguage, IntPtr lParam)
        {
            List<Resource> resources = null;
            ResourceId type = new ResourceId(lpszType);
            if (!_resources.TryGetValue(type, out resources))
            {
                resources = new List<Resource>();
                _resources[type] = resources;
            }

            ResourceId name = new ResourceId(lpszName);
            IntPtr hResource = Kernel32.FindResourceEx(hModule, lpszType, lpszName, wIDLanguage);
            IntPtr hResourceGlobal = Kernel32.LoadResource(hModule, hResource);
            int size = Kernel32.SizeofResource(hModule, hResource);
            resources.Add(CreateResource(hModule, hResourceGlobal, type, name, wIDLanguage, size));
            return true;
        }

        /// <summary>
        /// Save resource to a file.
        /// </summary>
        /// <param name="filename">Target filename.</param>
        public void Save(string filename)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Dispose resource info object.
        /// </summary>
        public void Dispose()
        {
            Unload();
        }

        /// <summary>
        /// A collection of resources.
        /// </summary>
        /// <param name="type">Resource type.</param>
        /// <returns>A collection of resources of a given type.</returns>
        public List<Resource> this[Kernel32.ResourceTypes type]
        {
            get
            {
                return _resources[new ResourceId(type)];
            }
            set
            {
                _resources[new ResourceId(type)] = value;
            }
        }

        /// <summary>
        /// A collection of resources.
        /// </summary>
        /// <param name="type">Resource type.</param>
        /// <returns>A collection of resources of a given type.</returns>
        public List<Resource> this[string type]
        {
            get
            {
                return _resources[new ResourceId(type)];
            }
            set
            {
                _resources[new ResourceId(type)] = value;
            }
        }

        #region IEnumerable<Resource> Members

        /// <summary>
        /// Enumerates all resources within this resource info collection.
        /// </summary>
        /// <returns>Resources enumerator.</returns>
        public IEnumerator<Resource> GetEnumerator()
        {
            Dictionary<ResourceId, List<Resource>>.Enumerator resourceTypesEnumerator = _resources.GetEnumerator();
            while(resourceTypesEnumerator.MoveNext())
            {
                List<Resource>.Enumerator resourceEnumerator = resourceTypesEnumerator.Current.Value.GetEnumerator();
                while (resourceEnumerator.MoveNext())
                {
                    yield return resourceEnumerator.Current;
                }                
            }
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Enumerates all resources within this resource info collection.
        /// </summary>
        /// <returns>Resources enumerator.</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
dB.
Team Leader Application Security Inc., www.appsecinc.com
United States United States
Daniel Doubrovkine has been in software engineering for twelve years and is currently development manager at Application Security Inc. in New York City. He has been involved in many software ventures, including Xo3 and Vestris Inc, was a development lead at Microsoft Corp. in Redmond, and director of Engineering at Visible Path Corp. in New York City. Daniel also builds and runs a foodie website, http://www.foodcandy.com.

Comments and Discussions