WM_GETICON 有时不返回图标句柄

发布于 2024-10-30 07:02:32 字数 785 浏览 3 评论 0原文

我试图显示所有窗口标题,包括相应的图标,就像 Windows 任务管理器那样。但这仅在一定程度上有效 - 尽管我能够获取窗口的标题栏文本,但该图标并不总是可用。

为了获取图标,我将 WM_GETICON 消息传递给 SendMessage (source):

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 任务管理器和任务栏上,它们显示得很好。

造成这种情况的原因是什么?我该如何解决这个问题?

I'm trying to show all window titles including the corresponding icons, much like Windows Task Manager does. This works only to a certain extent though - although I am able to get the windows' title bar texts, the icon is not always available.

For getting the icon I pass the WM_GETICON message to SendMessage (source):

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 some windows, this returns just the correct icon. For others, it returns Nothing since IconHandle is equal to 0. In Windows Task Manager and on the taskbar they show up just fine.

What could be the cause of this, and how might I go about solving this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤蝉 2024-11-06 07:02:32

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

基本上,它尝试 WM_GETICON 来获取大图标。如果失败,它会调用 GetClassLong,其中有时包含图标。否则,使用WM_GETICON来获取小图标。在前两种情况下,我必须将其转换为位图,将其大小调整为 16x16(我需要该大小),然后将其转换回图标。

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

Using some copy-and-pasting and messing around, I ended up with the following code... But it now works for all windows.

Basically, it tries WM_GETICON to get a large icon. If it fails, it calls GetClassLong, which sometimes includes the icon. Otherwise, WM_GETICON is used to get the small icon. In the first two cases, I had to convert it into a Bitmap, resize it to 16x16 (I need that size), and then convert it back to an 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文