windows - WM\_GETICON returnerer nogle gange ingen ikonhåndtag

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger at vise alle vinduetitler, herunder de tilsvarende ikoner, ligesom Windows Task Manager gør. Dette virker kun i et vist omfang selvom jeg - selvom jeg er i stand til at få vinduerne 'titellinjen, er ikonet ikke altid tilgængeligt.


For at få ikonet sender jeg WM\_GETICON beskeden til SendMessage (kilde): [13]


Public Const WM\_GETICON As UInteger = &H7F
Public Function GetWindowIcon(ByVal WindowHandle As IntPtr) As Icon
    Dim IconHandle As IntPtr = SendMessage(WindowHandle, WM\_GETICON, 0, 0)
    If Not IconHandle = IntPtr.Zero Then
        Return Icon.FromHandle(IconHandle)
    Else
        Return Nothing
    End If
End Function


For nogle vinduer returnerer dette kun det korrekte ikon. For andre returnerer den Nothing siden IconHandle er lig med 0. I Windows Task Manager og på proceslinjen vises de bare fint.


Hvad kan der være årsagen til, og hvordan kan jeg gå på at løse dette?

Bedste reference


Ved hjælp af nogle kopi og klipning og messing rundt, endte jeg med følgende kode ... Men det virker nu for alle vinduer.


Grundlæggende forsøger den WM\_GETICON at få et stort ikon. Hvis det fejler, kalder det GetClassLong, som undertiden indeholder ikonet. Ellers bruges WM\_GETICON til at få det lille ikon. I de to første tilfælde måtte jeg konvertere det til en Bitmap, ændre størrelsen på 16x16 (jeg har brug for den størrelse) og derefter konvertere den til en Icon.


Public Function GetClassLongPtr(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As IntPtr
    If IntPtr.Size > 4 Then
        Return GetClassLongPtr64(hWnd, nIndex)
    Else
        Return New IntPtr(GetClassLongPtr32(hWnd, nIndex))
    End If
End Function

<DllImport("user32.dll", EntryPoint:="GetClassLong")> \_
Public Function GetClassLongPtr32(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As UInteger
End Function

<DllImport("user32.dll", EntryPoint:="GetClassLongPtr")> \_
Public Function GetClassLongPtr64(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As IntPtr
End Function

<DllImport("user32.dll")> \_
Public Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Int32, ByVal wParam As Boolean, ByVal lParam As Int32) As Integer
End Function


Public Const WM\_GETICON As UInteger = &H7F
Public Function GetWindowIcon(ByVal WindowHandle As IntPtr) As Icon
    Dim IconHandle As IntPtr = SendMessage(WindowHandle, WM\_GETICON, 1, 0)
    If Not IconHandle = IntPtr.Zero Then
        Dim \_icon = Icon.FromHandle(IconHandle)
        Dim bmp = \_icon.ToBitmap
        Dim scale\_factor As Single = 16 / \_icon.Size.Width

        ' Make a bitmap for the result.
        Dim bm\_dest As New Bitmap( \_
            CInt(bmp.Width * scale\_factor), \_
            CInt(bmp.Height * scale\_factor))

        ' Make a Graphics object for the result Bitmap.
        Dim gr\_dest As Graphics = Graphics.FromImage(bm\_dest)

        ' Copy the source image into the destination bitmap.
        gr\_dest.DrawImage(bmp, 0, 0, \_
            bm\_dest.Width + 1, \_
            bm\_dest.Height + 1)

        Return MakeIcon(bm\_dest, 16, False)
        'Return Icon.FromHandle(IconHandle)
    Else
        IconHandle = GetClassLongPtr(WindowHandle, -34)
        If Not IconHandle = IntPtr.Zero Then
            Dim \_icon = Icon.FromHandle(IconHandle)

            Dim bmp = \_icon.ToBitmap
            Dim scale\_factor As Single = 16 / \_icon.Size.Width

            ' Make a bitmap for the result.
            Dim bm\_dest As New Bitmap( \_
                CInt(bmp.Width * scale\_factor), \_
                CInt(bmp.Height * scale\_factor))

            ' Make a Graphics object for the result Bitmap.
            Dim gr\_dest As Graphics = Graphics.FromImage(bm\_dest)

            ' Copy the source image into the destination bitmap.
            gr\_dest.DrawImage(bmp, 0, 0, \_
                bm\_dest.Width + 1, \_
                bm\_dest.Height + 1)

            Return MakeIcon(bm\_dest, 16, False)
        Else
            IconHandle = SendMessage(WindowHandle, WM\_GETICON, 1, 0)
            If Not IconHandle = IntPtr.Zero Then
                Dim \_icon = Icon.FromHandle(IconHandle)
                Dim bmp = \_icon.ToBitmap
                Dim scale\_factor As Single = 16 / \_icon.Size.Width

                ' Make a bitmap for the result.
                Dim bm\_dest As New Bitmap( \_
                    CInt(bmp.Width * scale\_factor), \_
                    CInt(bmp.Height * scale\_factor))

                ' Make a Graphics object for the result Bitmap.
                Dim gr\_dest As Graphics = Graphics.FromImage(bm\_dest)

                ' Copy the source image into the destination bitmap.
                gr\_dest.DrawImage(bmp, 0, 0, \_
                    bm\_dest.Width + 1, \_
                    bm\_dest.Height + 1)

                Return MakeIcon(bm\_dest, 16, False)
            Else
                Return Nothing
            End If
        End If
    End If
End Function



''' <summary>
''' Converts an image into an icon.
''' </summary>
''' <param name="img">The image that shall become an icon</param>
''' <param name="size">The width and height of the icon. Standard
''' sizes are 16x16, 32x32, 48x48, 64x64.</param>
''' <param name="keepAspectRatio">Whether the image should be squashed into a
''' square or whether whitespace should be put around it.</param>
''' <returns>An icon!!</returns>
Private Function MakeIcon(ByVal img As Image, ByVal size As Integer, ByVal keepAspectRatio As Boolean) As Icon
    Dim square As New Bitmap(size, size)
    ' create new bitmap
    Dim g As Graphics = Graphics.FromImage(square)
    ' allow drawing to it
    Dim x As Integer, y As Integer, w As Integer, h As Integer
    ' dimensions for new image
    If Not keepAspectRatio OrElse img.Height = img.Width Then
        ' just fill the square
        x = 0
        y = 0
        ' set x and y to 0
        ' set width and height to size
        w = size
        h = size
    Else
        ' work out the aspect ratio
        Dim r As Single = CSng(img.Width) / CSng(img.Height)

        ' set dimensions accordingly to fit inside size^2 square
        If r > 1 Then
            ' w is bigger, so divide h by r
            w = size
            h = CInt(Math.Truncate(CSng(size) / r))
            x = 0
            ' center the image
            y = (size - h)  2
        Else
            ' h is bigger, so multiply w by r
            w = CInt(Math.Truncate(CSng(size) * r))
            h = size
            y = 0
            ' center the image
            x = (size - w)  2
        End If
    End If

    ' make the image shrink nicely by using HighQualityBicubic mode
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default
    g.DrawImage(img, x, y, w, h)
    ' draw image with specified dimensions
    'g.Flush()
    ' make sure all drawing operations complete before we get the icon
    ' following line would work directly on any image, but then
    ' it wouldn't look as nice.
    Return Icon.FromHandle(square.GetHicon())
End Function