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
}
}