WM_GETICON有时不返回图标句柄

时间:2011-04-04 18:03:21

标签: windows vb.net winapi sendmessage

我正在尝试显示所有窗口标题,包括相应的图标,就像Windows任务管理器一样。这只在某种程度上起作用 - 尽管我能够获得windows的标题栏文本,但图标并不总是可用。

要获取图标,我将WM_GETICON消息传递给SendMessagesource):

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

对于某些窗口,这会返回正确的图标。对于其他人,它会返回Nothing,因为IconHandle等于0。在Windows任务管理器和任务栏上,它们显示正常。

这可能是什么原因,我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:3)

使用一些复制粘贴和乱码,我最终得到了以下代码......但它现在适用于所有窗口。

基本上,它会尝试WM_GETICON来获取一个大图标。如果失败,则会调用GetClassLong,有时会包含图标。否则,WM_GETICON用于获取小图标。在前两种情况下,我必须将其转换为Bitmap,将其大小调整为16x16(我需要该大小),然后将其转换回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