November 9, 2004

EnumResourceNames in C#

EnumResourceNames is one of the tricky functions which uses a callback.

But the main problem is, that in the callback it either returns IDs or strings in the same parameter! To call this function from C# you have to do some own marshaling… To differentiate between IDs and strings they did a simple trick: If the higher part of the DWORD is 0, then it is an ID. It uses that fact that you cannot allocate memory in the region of 0×00000000 to 0×0000FFFF.

Here is a full working example which also handles IDs/strings (I also added this example to pinvoke.net)

  using System;
  using System.Runtime.InteropServices;

  namespace EnumResNamesCS
  {
    class Class1
    {
      private const uint RT_CURSOR = 0x00000001;
      private const uint RT_BITMAP = 0x00000002;
      private const uint RT_ICON = 0x00000003;
      private const uint RT_MENU = 0x00000004;
      private const uint RT_DIALOG = 0x00000005;
      private const uint RT_STRING = 0x00000006;
      private const uint RT_FONTDIR = 0x00000007;
      private const uint RT_FONT = 0x00000008;
      private const uint RT_ACCELERATOR = 0x00000009;
      private const uint RT_RCDATA = 0x00000010;
      private const uint RT_MESSAGETABLE = 0x00000011;

      private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;

      [DllImport("kernel32.dll", SetLastError = true)]
      private static extern IntPtr LoadLibraryEx(
        string lpFileName,
        IntPtr hFile,
        uint dwFlags);

      [DllImport("kernel32.dll", SetLastError = true)]
      private static extern bool FreeLibrary(IntPtr hModule);

      [DllImport("kernel32.dll", EntryPoint = "EnumResourceNamesW",
        CharSet = CharSet.Unicode, SetLastError = true)]
      static extern bool EnumResourceNamesWithName(
        IntPtr hModule,
        string lpszType,
        EnumResNameDelegate lpEnumFunc,
        IntPtr lParam);

      [DllImport("kernel32.dll", EntryPoint = "EnumResourceNamesW",
        CharSet = CharSet.Unicode, SetLastError = true)]
      static extern bool EnumResourceNamesWithID(
        IntPtr hModule,
        uint lpszType,
        EnumResNameDelegate lpEnumFunc,
        IntPtr lParam);

      private delegate bool EnumResNameDelegate(
        IntPtr hModule,
        IntPtr lpszType,
        IntPtr lpszName,
        IntPtr lParam);

      private static bool IS_INTRESOURCE(IntPtr value)
      {
        if ( ((uint) value) > ushort.MaxValue)
          return false;
        return true;
      }
      private static uint GET_RESOURCE_ID(IntPtr value)
      {
        if (IS_INTRESOURCE(value)  true)
          return (uint) value;
        throw new System.NotSupportedException("value is not an ID!");
      }
      private static string GET_RESOURCE_NAME(IntPtr value)
      {
        if (IS_INTRESOURCE(value)  true)
          return value.ToString();
        return Marshal.PtrToStringUni((IntPtr) value);
      }

      [STAThread]
      static void Main(string[] args)
      {
        IntPtr hMod = LoadLibraryEx(@”path to exe/dllfile”,
          IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
        if (EnumResourceNamesWithID(hMod, RT_ICON,
          new EnumResNameDelegate(EnumRes), IntPtr.Zero) == false)
        {
          Console.WriteLine(“gle: {0}”, Marshal.GetLastWin32Error());
        }
        FreeLibrary(hMod);
      }

      static bool EnumRes(IntPtr hModule,
        IntPtr lpszType,
        IntPtr lpszName,
        IntPtr lParam)
      {
        Console.WriteLine(“Type: {0}”, GET_RESOURCE_NAME(lpszType));
        Console.WriteLine(“Name: {0}”, GET_RESOURCE_NAME(lpszName));
        return true;
      }
    }
  }

Posted 3 years, 3 months ago on November 9, 2004
The trackback url for this post is http://blog.kalmbachnet.de/bblog/trackback.php/26/

Comments have now been turned off for this post