Search code examples
vb.netresourcesenumerate

Enumerating native resources


This question is related to Visual Basic .NET 2010

How do I enumerate the "native" resources (such as icon, version info, etc) of a win32 executable file?

I found little to no documentation on it, and what I found simply did not work. I've tried the example provided here so far http://www.pinvoke.net/default.aspx/kernel32.EnumResourceNames. It's all I could find on the subject.

Help is much appreciated.


Solution

  • It isn't that clear what your hangup might be. The declarations you found at pinvoke.net are only so-so, not an uncommon problem. The probable hangup is that both the resource type and the resource name can either be a number or a string. So the pinvoke declaration should declare them as IntPtr and, if they have the right value, convert them to a string dynamically.

    Another thing you have to do is to first enumerate the resource types in the file, then enumerate the resources of that type.

    Some code to play with:

    Imports System.Runtime.InteropServices
    Imports System.ComponentModel
    Imports System.Linq
    
    Module Module1
        Sub Main()
            Dim handle = LoadLibrary("user32.dll")
            If handle = IntPtr.Zero Then
                Throw New Win32Exception
            End If
            If Not EnumResourceTypes(handle, AddressOf EnumTypesCallback, IntPtr.Zero) Then
                Throw New Win32Exception
            End If
            Console.ReadLine()
        End Sub
    
        Function EnumTypesCallback(hModule As IntPtr, lpszType As IntPtr, lParam As IntPtr) As Boolean
            EnumResourceNames(hModule, lpszType, AddressOf EnumResourceCallback, IntPtr.Zero)
            Return True
        End Function
    
        Function EnumResourceCallback(hModule As IntPtr, lpszType As IntPtr, ByVal lpszName As IntPtr, ByVal lParam As IntPtr) As Boolean
            Dim type As String = lpszType.ToInt32().ToString()
            If [Enum].GetValues(GetType(ResourceType)).Cast(Of Integer).Contains(lpszType.ToInt32()) Then
                type = [Enum].GetName(GetType(ResourceType), lpszType.ToInt32())
            ElseIf lpszType.ToInt32() > &HFFFF Then
                type = Marshal.PtrToStringUni(lpszType)
            End If
            Dim name As String = lpszName.ToInt32().ToString()
            If lpszName.ToInt32() > &HFFFF Then
                name = Marshal.PtrToStringUni(lpszName)
            End If
            Console.WriteLine("Resource type={0}, id={1}", type, name)
            Return True
        End Function
    
    
        Private Delegate Function EnumResNameProcDelegate(ByVal hModule As IntPtr, ByVal lpszType As IntPtr, ByVal lpszName As IntPtr, ByVal lParam As IntPtr) As Boolean
        Private Delegate Function EnumResTypeProc(hModule As IntPtr, lpszType As IntPtr, lParam As IntPtr) As Boolean
    
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
        Public Function LoadLibrary(ByVal lpFileName As String) As IntPtr
        End Function
    
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
        Private Function EnumResourceTypes(ByVal hModule As IntPtr, ByVal lpEnumFunc As EnumResTypeProc, ByVal lParam As IntPtr) As Boolean
        End Function
    
        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
        Private Function EnumResourceNames(ByVal hModule As IntPtr, ByVal lpszType As IntPtr, ByVal lpEnumFunc As EnumResNameProcDelegate, ByVal lParam As IntPtr) As Boolean
        End Function
    
        Public Enum ResourceType
            CURSOR = 1
            BITMAP = 2
            ICON = 3
            MENU = 4
            DIALOG = 5
            [STRING] = 6
            FONTDIR = 7
            FONT = 8
            ACCELERATOR = 9
            RCDATA = 10
            MESSAGETABLE = 11
            GROUP_CURSOR = 12
            GROUP_ICON = 14
            VERSION = 16
            DLGINCLUDE = 17
            PLUGPLAY = 19
            VXD = 20
            ANICURSOR = 21
            ANIICON = 22
            HTML = 23
            MANIFEST = 24
        End Enum
    End Module
    

    Output on Windows 8.1:

    Resource type=MUI, id=1
    Resource type=WEVT_TEMPLATE, id=1
    Resource type=CURSOR, id=92
    Resource type=CURSOR, id=93
    etc...
    Resource type=BITMAP, id=36
    Resource type=BITMAP, id=136
    etc..
    Resource type=ICON, id=1
    Resource type=ICON, id=2
    etc..
    Resource type=MENU, id=1
    Resource type=MENU, id=4
    etc..
    Resource type=DIALOG, id=9
    Resource type=STRING, id=1
    Resource type=STRING, id=44
    etc..
    Resource type=MESSAGETABLE, id=1
    Resource type=GROUP_CURSOR, id=100
    Resource type=GROUP_CURSOR, id=101
    etc..
    Resource type=GROUP_ICON, id=100
    Resource type=GROUP_ICON, id=101
    etc..
    Resource type=VERSION, id=1
    Resource type=ANICURSOR, id=32665
    Resource type=ANICURSOR, id=32666
    Resource type=ANICURSOR, id=32669
    

    Compare to what you see when you use File + Open + File, select c:\windows\syswow64\user32.dll (won't work on Express).