Programming Field

実行可能ファイルからのアイコンの抽出

実行可能ファイルからアイコンを抽出する簡単な方法は、ExtractIcon または ExtractIconEx (Win32 のみ) を使います。その定義は以下の通りです。

[C/C++]

HICON STDAPICALLTYPE ExtractIconA(HINSTANCE hInst,
    LPCSTR lpszExeFileName, UINT nIconIndex);
HICON STDAPICALLTYPE ExtractIconW(HINSTANCE hInst,
    LPCWSTR lpszExeFileName, UINT nIconIndex);
UINT STDAPICALLTYPE ExtractIconExA(LPCSTR lpszFile, int nIconIndex,
    HICON *phiconLarge, HICON *phiconSmall, UINT nIcons);
UINT STDAPICALLTYPE ExtractIconExW(LPCWSTR lpszFile, int nIconIndex,
    HICON *phiconLarge, HICON *phiconSmall, UINT nIcons);
#ifdef UNICODE
#define ExtractIcon     ExtractIconW
#define ExtractIconEx   ExtractIconExW
#else
#define ExtractIcon     ExtractIconA
#define ExtractIconEx   ExtractIconExA
#endif // !UNICODE

[VB 6.0]

Declare Function ExtractIcon Lib "shell32.dll" Alias "ExtractIconA" _
    (ByVal hInst As Long, ByVal lpszExeFileName As String, _
    ByVal nIconIndex As Long) As Long
Declare Function ExtractIconEx Lib "shell32.dll" Alias "ExtractIconExA" _
    (ByVal lpszFile As String, ByVal nIconIndex As Long, _
    ByRef phiconLarge As Long, ByRef phiconSmall As Long, _
    ByVal nIcons As Long) As Long

[VB.NET]

Declare Ansi Function ExtractIcon Lib "shell32.dll" Alias "ExtractIconA" _
    (ByVal hInst As System.IntPtr, ByVal lpszExeFileName As String, _
    ByVal nIconIndex As Integer) As System.IntPtr
Declare Ansi Function ExtractIconEx Lib "shell32.dll" Alias "ExtractIconExA" _
    (ByVal lpszFile As String, ByVal nIconIndex As Integer, _
    ByRef phiconLarge As System.IntPtr, ByRef phiconSmall As System.IntPtr, _
    ByVal nIcons As Integer) As Integer
hInst アプリケーションのインスタンスハンドルを指定します。(取得できない場合は、ExtractIconEx を使ったほうが良いかもしれません。)
lpszExeFileName / lpszFile アイコンを取得するファイル名を指定します。このファイル名は、EXE、DLL、ICO などの拡張子のファイルです。
nIconIndex 取得するアイコンのインデックスを、0 から始まる値で指定します。また、負の値(-100 など)を指定すると、その絶対値(-100 → 100)を ID に持つアイコンを取得します。
ExtractIconEx の場合は、ここで指定した値に当たるアイコンから nIcons で指定した数だけアイコンを取得します。たとえば、ここで 1 を指定し、nIcons で 4 を指定すると、phiconLarge および phiconSmall に、インデックス 1~4 のアイコンが格納されます。
phiconLarge, phiconSmall アイコンを受け取る HICON 型([VB] Long[VB.NET] System.IntPtr) の配列を指定します。この配列のアイテム数は、nIcons の値以上でなければなりません。phiconLarge には大きいアイコン(32 x 32)、phiconSmall には小さいアイコン(16 x 16)が格納されます。
phiconLarge と phiconSmall の両方に NULL (0) を指定し、nIconIndex に -1、nIcons に 0 (これは念のため)を指定することで、ファイルに含まれるアイコンの総数を取得することができます。
nIcons 取得するアイコンの数を指定します。

※ ExtractIcon の戻り値は HICON ([VB] Long[VB.NET] System.IntPtr) です。取得したアイコンのハンドル(HICON)は、使用後必ず DestroyIcon で破棄する必要があります。

これらの関数は、データ内からアイコンデータを取り出し、そのデータを元に自動的にアイコンのハンドルを作成してくれます。

ところが、これらの関数では、リソース ID からアイコンを作成するのに失敗することがあります(どの条件で失敗するかは忘れた・・・)。レジストリのファイル関連付けのデータにあるような、アイコンを含むファイル名と ID (ここでのデータはマイナスになっていて、絶対値が ID の値になってます) からアイコンを作成したり、16x16 や 32x32 以外のアイコンを取得する(ExtractIcon(Ex)ではできない)には、LoadLibraryExFindResourceLookupIconIdFromDirectoryExCreateIconFromResource などの関数を使って取得することが出来ます。

以下に例を示します。

[C/C++]

// EnumResourceNames で使うデータ
struct _CMyExtractIconData
{
    // 取得するアイコンのインデックス
    int nIndex;
    // 現在列挙しているアイコンのインデックス
    int nNowPos;
    // 見つかったかどうか
    bool bFound;
    // true の場合は uID、false の場合は lpszName を使う
    // (リソースの ID が文字列の場合を考慮)
    bool bIsID;
    // リソース ID (数値)
    UINT uID;
    // リソース ID (文字列)
    LPTSTR lpszName;
};

// EnumResourceNames のコールバック関数
extern "C" BOOL CALLBACK _MyEnumResNameProc(HINSTANCE hInstance, LPCTSTR lpszType,
    LPTSTR lpszName, _CMyExtractIconData FAR* pData)
{
    // 現在のインデックスが欲しいアイコンのインデックスと一致するかどうか
    if (pData->nNowPos == pData->nIndex)
    {
        // 一致 → 見つかった
        pData->bFound = true;
        // lpszName の上位ワードが 0 のときは ID が数値
        // (文字列のポインタで上位ワードが 0 のものはまず無い)
        if (pData->bIsID = (HIWORD(lpszName) == 0))
            pData->uID = LOWORD(lpszName);
        else
            // 文字列のコピーを作成する
            pData->lpszName = _tcsdup(lpszName);
        // FALSE を返して列挙を終了する
        return FALSE;
    }
    // 次のインデックスにしておく
    pData->nNowPos++;
    return TRUE;
}

// lpszPathName:  アイコンのデータが入っているアプリケーション/DLL
// nIndexOrID:    正の値(0 含む)ならインデックス、負の値なら ID
// bSmallIcon:    16x16 のサイズのアイコンを取得するかどうか (false なら 32x32)
HICON MyExtractIcon(LPCTSTR lpszPathName, int nIndexOrID, bool bSmallIcon)
{
    HINSTANCE hInstance;
    HICON hIconRet;
    _CMyExtractIconData data;
    HRSRC hRes, hRes2;
    HGLOBAL hMem, hMem2;
    LPVOID lpv, lpv2;

    if (!lpszPathName)
        return NULL;
    // 実行はしないので LOAD_LIBRARY_AS_DATAFILE を指定する
    hInstance = LoadLibraryEx(lpszPathName, NULL,
        LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
    if (!hInstance)
        return NULL;

    hIconRet = NULL;
    if (nIndexOrID < 0)
    {
        // 負の値 = 識別子
        // LoadIcon や LoadImage だと Win95/98/Me で読み込めない・・・
        data.bIsID = true;
        data.uID = (UINT) (-nIndexOrID);
    }
    else
    {
        // 正の値 = インデックス
        // リソースを列挙して読み込み
        data.nIndex = nIndexOrID;
        data.nNowPos = 0;
        data.bFound = false;
        EnumResourceNames(hInstance, RT_GROUP_ICON,
            (ENUMRESNAMEPROC) _MyEnumResNameProc,
            (LPARAM)(_CMyExtractIconData FAR*) &data);
        // 見つからなかったら終了
        if (!data.bFound)
        {
            FreeLibrary(hInstance);
            return NULL;
        }
    }

    // グループアイコン リソースを取得
    // (サイズや色情報が複数含まれている可能性もあるため)
    hRes = FindResource(hInstance,
        data.bIsID ? MAKEINTRESOURCE(data.uID) : (LPCTSTR) data.lpszName,
        RT_GROUP_ICON);
    if (hRes)
    {
        // FindResource のあとは LoadResource、LockResource
        hMem = LoadResource(hInstance, hRes);
        lpv = LockResource(hMem);
        // アイコン本体の ID (指定したサイズ、色を持つアイコン) を取得する関数
        // (第 2 引数が FALSE の場合カーソルを取得)
        // (bSmallIcon が true なら 16x16、false なら 32x32)
        // (色はデフォルトのものを使用する)
        // ※ ここでサイズを任意のものに指定できます。(48x48 など)
        data.uID = LookupIconIdFromDirectoryEx((PBYTE) lpv, TRUE,
            bSmallIcon ? 16 : 32, bSmallIcon ? 16 : 32, LR_DEFAULTCOLOR);
        // アイコン本体のリソースを取得
        hRes2 = FindResource(hInstance, MAKEINTRESOURCE(data.uID), RT_ICON);
        if (hRes2)
        {
            // FindResource のあとは LoadResource、LockResource
            hMem2 = LoadResource(hInstance, hRes2);
            lpv2 = LockResource(hMem2);
            // リソースからアイコンを作成
            hIconRet = CreateIconFromResource((PBYTE) lpv2,
                SizeofResource(hInstance, hRes2),
                TRUE, 0x00030000);
            // Win32 ではロック解除、解放はいらない (呼び出せない)
            //UnlockResource(hMem2);
            //FreeResource(hRes2);
        }
        //UnlockResource(hMem);
        //FreeResource(hRes);
    }

    // 文字列を使用している場合は解放する
    if (!data.bIsID)
        free(data.lpszName);

    FreeLibrary(hInstance);
    return hIconRet;
}

途中で「LoadIcon や LoadImage だと Win95/98/Me で読み込めない・・・」と書いてあるのは、LoadLibraryEx で読み込んだ実行可能ファイルに対して、Win95/98/Me では LoadIcon LoadImage などでリソースを読み込めないため、結局 FindResource LoadResource を使う必要がある、という事です。(これは LoadBitmap などでも同じだと思われます。)

[VB 6.0]

※ コメントがほとんど入っていません。動作自体は上と同じなのでそれを参考にしてください。

Public Const LR_DEFAULTCOLOR     As Long = &H0&
Public Const LR_MONOCHROME       As Long = &H1&
Public Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _
    (ByRef Dest As Any, ByRef Source As Any, ByVal Length As Long)
Public Declare Function lstrlen Lib "kernel32.dll" Alias "lstrlenA" _
    (ByVal lpszString As Any) As Long

Public Type MyExtractIconData
    Index As Long
    NowPos As Long
    Found As Boolean
    IsID As Boolean
    ID As Long
    Name As String
End Type

Public Const DONT_RESOLVE_DLL_REFERENCES   As Long = &H1&
Public Const LOAD_LIBRARY_AS_DATAFILE      As Long = &H2&
Public Const LOAD_WITH_ALTERED_SEARCH_PATH As Long = &H8&
Public Const LOAD_IGNORE_CODE_AUTHZ_LEVEL  As Long = &H10&
Public Declare Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExA" _
    (ByVal lpLibFileName As String, ByVal hFile As Long, ByVal dwFlags As Long) As Long
Public Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hModule As Long) As Long
Public Const RT_CURSOR           As Long = 1
Public Const RT_BITMAP           As Long = 2
Public Const RT_ICON             As Long = 3
Public Const RT_MENU             As Long = 4
Public Const RT_DIALOG           As Long = 5
Public Const RT_STRING           As Long = 6
Public Const RT_FONTDIR          As Long = 7
Public Const RT_FONT             As Long = 8
Public Const RT_ACCELERATOR      As Long = 9
Public Const RT_RCDATA           As Long = 10
Public Const RT_MESSAGETABLE     As Long = 11
Public Const RT_GROUP_CURSOR     As Long = 12
Public Const RT_GROUP_ICON       As Long = 14
Public Const RT_VERSION          As Long = 16
Public Const RT_DLGINCLUDE       As Long = 17
Public Const RT_PLUGPLAY         As Long = 19
Public Const RT_VXD              As Long = 20
Public Const RT_ANICURSOR        As Long = 21
Public Const RT_ANIICON          As Long = 22
Public Const RT_HTML             As Long = 23
Public Const RT_MANIFEST         As Long = 24
Public Declare Function EnumResourceNames Lib "kernel32.dll" Alias "EnumResourceNamesA" _
    (ByVal hModule As Long, ByVal lpszType As Any, _
    ByVal lpEnumFunc As Long, ByRef lParam As Any) As Long
Public Declare Function FindResource Lib "kernel32.dll" Alias "FindResourceA" _
    (ByVal hModule As Long, ByVal lpName As Any, ByVal lpType As Any) As Long
Public Declare Function LoadResource Lib "kernel32.dll" _
    (ByVal hModule As Long, ByVal hResInfo As Long) As Long
Public Declare Function LockResource Lib "kernel32.dll" (ByVal hResData As Long) As Long
Public Declare Function SizeofResource Lib "kernel32.dll" _
    (ByVal hModule As Long, ByVal hResInfo As Long) As Long
Public Declare Function LookupIconIdFromDirectoryEx Lib "user32.dll" _
    (ByVal pResBits As Long, ByVal fIcon As Long, ByVal cxDesired As Long, _
    ByVal cyDesired As Long, ByVal Flags As Long) As Long
Public Declare Function CreateIconFromResource Lib "user32.dll" _
    (ByVal pResBits As Long, ByVal dwResSize As Long, ByVal fIcon As Long, _
    ByVal dwVer As Long) As Long

' ここまで宣言部
' ここから関数定義

Public Function MyEnumResNameProc(ByVal hInst As Long, ByVal lpszType As Long, _
    ByVal lpszName As Long, ByRef Data As MyExtractIconData) As Long
    Dim ln As Long
    If Data.NowPos = Data.Index Then
        Data.Found = True
        Data.IsID = ((lpszName And &HFFFF0000) = 0)
        If Not Data.IsID Then
            ln = lstrlen(lpszName)
            Data.Name = VBA.Strings.String$(ln + 1, 0)
            Call CopyMemory(ByVal Data.Name, ByVal lpszName, ln)
            Data.Name = VBA.Strings.Left$(Data.Name, _
                VBA.Strings.InStr(Data.Name, VBA.Chr$(0)) - 1)
            ' EnumResourceNames で MyExtractIconData を渡すときに
            ' 文字列の変換が発生するので、ここで対処しておく
            Data.Name = VBA.Strings.StrConv(Data.Name, vbFromUnicode)
        Else
            Data.ID = (lpszName And &HFFFF&)
        End If
        MyEnumResNameProc = 0
        Exit Function
    End If
    Data.NowPos = Data.NowPos + 1
    MyEnumResNameProc = 1
End Function

Public Function MyExtractIcon(ByVal PathName As String, ByVal IndexOrID As Long, _
    ByVal SmallIcon As Boolean)
    Dim hInstance As Long
    Dim hRes As Long, hRes2 As Long
    Dim hMem As Long, hMem2 As Long
    Dim lpv As Long, lpv2 As Long
    Dim Data As MyExtractIconData

    MyExtractIcon = 0
    hInstance = LoadLibraryEx(PathName, 0, LOAD_LIBRARY_AS_DATAFILE Or _
        LOAD_WITH_ALTERED_SEARCH_PATH)
    If hInstance = 0 Then Exit Function

    If IndexOrID < 0 Then
        Data.IsID = True
        Data.ID = -(IndexOrID + 1)
        Data.Found = True
    Else
        Data.Index = IndexOrID
        Data.NowPos = 0
        Data.Found = False
        Call EnumResourceNames(hInstance, RT_GROUP_ICON, AddressOf MyEnumResNameProc, Data)
        If Not Data.Found Then
            Call FreeLibrary(hInstance)
            Exit Function
        End If
    End If

    If Data.IsID Then
        hRes = FindResource(hInstance, Data.ID, RT_GROUP_ICON)
    Else
        hRes = FindResource(hInstance, Data.Name, RT_GROUP_ICON)
    End If
    If hRes <> 0 Then
        hMem = LoadResource(hInstance, hRes)
        lpv = LockResource(hMem)
        Data.ID = LookupIconIdFromDirectoryEx(lpv, True, _
            VBA.Interaction.IIf(SmallIcon, 16, 32), VBA.Interaction.IIf(SmallIcon, 16, 32), _
            LR_DEFAULTCOLOR)
        If Data.ID <> 0 Then
            hRes2 = FindResource(hInstance, Data.ID, RT_ICON)
            hMem2 = LoadResource(hInstance, hRes2)
            lpv2 = LockResource(hMem2)
            MyExtractIcon = CreateIconFromResource(lpv2, _
                SizeofResource(hInstance, hRes2), 1, &H30000)
        End If
    End If
    Call FreeLibrary(hInstance)
End Function

[VB 6.0] ハンドルをオブジェクト(IPictureDisp、StdPicture など、ピクチャコントロールなどに設定できる型)にするには、「VB 6.0 における画像ハンドルの変換」を参照してください。

[VB.NET]

ついでに HICON → System.Drawing.Icon も行っています。

外部 DLL を呼び出すサンプルにひょっとしたらなるかもしれません

Imports System.Runtime.InteropServices

Module IconTestModule

    Public Const LR_DEFAULTCOLOR As Integer = &H0I
    Public Const LR_MONOCHROME As Integer = &H1I

    ' MyExtractIconData 用のデータ (Structure より Class の方が楽)
    Public Class MyExtractIconData
        Public Index As Integer
        Public NowPos As Integer
        Public Found As Boolean
        Public IsID As Boolean
        Public ID As UInteger
        Public Name As String
    End Class

    Public Const DONT_RESOLVE_DLL_REFERENCES As Integer = &H1I
    Public Const LOAD_LIBRARY_AS_DATAFILE As Integer = &H2I
    Public Const LOAD_WITH_ALTERED_SEARCH_PATH As Integer = &H8I
    Public Const LOAD_IGNORE_CODE_AUTHZ_LEVEL As Integer = &H10I
    Public Declare Ansi Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExA" _
     (ByVal lpLibFileName As String, ByVal hFile As System.IntPtr, _
     ByVal dwFlags As Integer) As System.IntPtr
    Public Declare Ansi Function FreeLibrary Lib "kernel32.dll" _
     (ByVal hModule As System.IntPtr) As Boolean
    Public Const RT_CURSOR As Integer = 1
    Public Const RT_BITMAP As Integer = 2
    Public Const RT_ICON As Integer = 3
    Public Const RT_MENU As Integer = 4
    Public Const RT_DIALOG As Integer = 5
    Public Const RT_STRING As Integer = 6
    Public Const RT_FONTDIR As Integer = 7
    Public Const RT_FONT As Integer = 8
    Public Const RT_ACCELERATOR As Integer = 9
    Public Const RT_RCDATA As Integer = 10
    Public Const RT_MESSAGETABLE As Integer = 11
    Public Const RT_GROUP_CURSOR As Integer = 12
    Public Const RT_GROUP_ICON As Integer = 14
    Public Const RT_VERSION As Integer = 16
    Public Const RT_DLGINCLUDE As Integer = 17
    Public Const RT_PLUGPLAY As Integer = 19
    Public Const RT_VXD As Integer = 20
    Public Const RT_ANICURSOR As Integer = 21
    Public Const RT_ANIICON As Integer = 22
    Public Const RT_HTML As Integer = 23
    Public Const RT_MANIFEST As Integer = 24

    ' コールバック関数をデリゲートで宣言します。
    Public Delegate Function EnumResNameProc(ByVal hInst As System.IntPtr, _
     ByVal lpszType As System.IntPtr, ByVal lpszName As System.IntPtr, _
     ByVal lParam As System.IntPtr) As Boolean

    Public Declare Ansi Function EnumResourceNames Lib "kernel32.dll" _
     Alias "EnumResourceNamesA" (ByVal hModule As System.IntPtr, _
     ByVal lpszType As System.IntPtr, ByVal lpEnumFunc As EnumResNameProc, _
     ByVal lParam As System.IntPtr) As Boolean

    ' 以下の 2 つは数値でも文字列でも呼び出せるようにしています。
    Public Declare Ansi Function FindResource Lib "kernel32.dll" Alias "FindResourceA" _
     (ByVal hModule As System.IntPtr, ByVal lpName As System.IntPtr, _
     ByVal lpType As System.IntPtr) As System.IntPtr
    Public Declare Ansi Function FindResource Lib "kernel32.dll" Alias "FindResourceA" _
     (ByVal hModule As System.IntPtr, ByVal lpName As String, _
     ByVal lpType As System.IntPtr) As System.IntPtr

    Public Declare Ansi Function LoadResource Lib "kernel32.dll" _
     (ByVal hModule As System.IntPtr, ByVal hResInfo As System.IntPtr) As System.IntPtr
    Public Declare Ansi Function LockResource Lib "kernel32.dll" _
     (ByVal hResData As System.IntPtr) As System.IntPtr
    Public Declare Ansi Function SizeofResource Lib "kernel32.dll" _
     (ByVal hModule As System.IntPtr, ByVal hResInfo As System.IntPtr) As Integer
    Public Declare Ansi Function LookupIconIdFromDirectoryEx Lib "user32.dll" _
     (ByVal pResBits As System.IntPtr, ByVal fIcon As Integer, ByVal cxDesired As Integer, _
     ByVal cyDesired As Integer, ByVal Flags As Integer) As Integer
    Public Declare Ansi Function CreateIconFromResource Lib "user32.dll" _
     (ByVal pResBits As System.IntPtr, ByVal dwResSize As Integer, ByVal fIcon As Integer, _
     ByVal dwVer As Integer) As System.IntPtr

    Public Declare Auto Function DestroyIcon Lib "user32.dll" _
     (ByVal hIcon As System.IntPtr) As Boolean

    Public Function MyEnumResNameProc(ByVal hInst As System.IntPtr, _
     ByVal lpszType As System.IntPtr, ByVal lpszName As System.IntPtr, _
     ByVal lParam As System.IntPtr) As Boolean
        Dim strName As String
        Dim ptr As GCHandle = GCHandle.FromIntPtr(lParam)
        Dim Data As MyExtractIconData
        Data = ptr.Target
        If Data.NowPos = Data.Index Then
            Data.Found = True
            Data.IsID = ((lpszName.ToInt32() And &HFFFF0000I) = 0)
            If Not Data.IsID Then
                strName = Marshal.PtrToStringAnsi(lpszName)
                Data.Name = strName
            Else
                Data.ID = (lpszName.ToInt32() And &HFFFFI)
            End If
            Return False
        End If
        Data.NowPos = Data.NowPos + 1
        Return True
    End Function

    Public Function MyExtractIcon(ByVal PathName As String, ByVal IndexOrID As Integer, _
     ByVal SmallIcon As Boolean) As System.IntPtr
        Dim hInstance As System.IntPtr
        Dim hRes As System.IntPtr, hRes2 As System.IntPtr
        Dim hMem As System.IntPtr, hMem2 As System.IntPtr
        Dim lpv As System.IntPtr, lpv2 As System.IntPtr
        Dim Data As MyExtractIconData, ptr As GCHandle

        hInstance = LoadLibraryEx(PathName, 0, LOAD_LIBRARY_AS_DATAFILE Or _
         LOAD_WITH_ALTERED_SEARCH_PATH)
        If hInstance = 0 Then Return 0

        Data = New MyExtractIconData
        If IndexOrID < 0 Then
            Data.IsID = True
            Data.ID = -(IndexOrID + 1)
            Data.Found = True
        Else
            Data.Index = IndexOrID
            Data.NowPos = 0
            Data.Found = False
            ptr = GCHandle.Alloc(Data)
            Call EnumResourceNames(hInstance, RT_GROUP_ICON, AddressOf MyEnumResNameProc, ptr)
            Call ptr.Free()
            If Not Data.Found Then
                Call FreeLibrary(hInstance)
                Return 0
            End If
        End If

        If Data.IsID Then
            hRes = FindResource(hInstance, CType(Data.ID, System.IntPtr), _
             CType(RT_GROUP_ICON, System.IntPtr))
        Else
            hRes = FindResource(hInstance, Data.Name, CType(RT_GROUP_ICON, System.IntPtr))
        End If
        If hRes <> 0 Then
            hMem = LoadResource(hInstance, hRes)
            lpv = LockResource(hMem)
            Data.ID = LookupIconIdFromDirectoryEx(lpv, True, _
             IIf(SmallIcon, 16, 32), IIf(SmallIcon, 16, 32), _
             LR_DEFAULTCOLOR)
            If Data.ID <> 0 Then
                hRes2 = FindResource(hInstance, CType(Data.ID, System.IntPtr), _
                 CType(RT_ICON, System.IntPtr))
                hMem2 = LoadResource(hInstance, hRes2)
                lpv2 = LockResource(hMem2)
                MyExtractIcon = CreateIconFromResource(lpv2, _
                 SizeofResource(hInstance, hRes2), 1, &H30000I)
            End If
        End If
        Call FreeLibrary(hInstance)
    End Function

    ' GetIconImageFromDLL は、DLL 名とインデックス (または絶対値が ID になる負の値)
    ' を指定するだけでアイコンオブジェクトを取得できます。
    ' PathName を省略すると "shell32.dll" になります
    Public Function GetIconImageFromDLL(ByVal PathName As String, ByVal IndexOrID As Integer, _
     Optional ByVal SmallIcon As Boolean = False) As System.Drawing.Icon
        Dim hIcon As System.IntPtr
        If PathName = Nothing OrElse PathName = "" Then PathName = "shell32.dll"
        hIcon = MyExtractIcon(PathName, IndexOrID, SmallIcon)
        If hIcon = 0 Then
            Return Nothing
        Else
            i = System.Drawing.Icon.FromHandle(hIcon)
            ' FromHandle では Dispose でアイコンを自動的に削除してくれないので作成しなおす
            i = i.Clone()
            Call DestroyIcon(hIcon)
            Return i
        End If
    End Function
End Module