You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时通过HWND获取第三方Windows应用窗口的图标位图?

获取Windows窗口图标位图(已知HWND)

要动态获取第三方Windows应用窗口的图标位图,核心是通过Win32 API先获取图标句柄,再将其转换为位图对象。以下是具体实现步骤和代码示例:

步骤1:获取窗口的图标句柄

窗口的图标存在三个层级优先级,依次尝试获取:

  1. 窗口自身设置的自定义图标(通过WM_GETICON消息获取)
  2. 窗口类默认的图标(通过GetClassLongPtr获取)
  3. 窗口所属进程可执行文件的默认图标(通过ExtractIconEx提取)

C++ 示例代码

#include <windows.h>
#include <shellapi.h>

HICON GetWindowIcon(HWND hWnd, bool getLargeIcon = true) {
    // 1. 尝试获取窗口自定义图标
    WPARAM wParam = getLargeIcon ? ICON_BIG : ICON_SMALL;
    HICON hIcon = (HICON)SendMessage(hWnd, WM_GETICON, wParam, 0);

    if (!hIcon) {
        // 2. 获取窗口类的默认图标
        int ptrIndex = getLargeIcon ? GCLP_HICON : GCLP_HICONSM;
        hIcon = (HICON)GetClassLongPtr(hWnd, ptrIndex);
    }

    if (!hIcon) {
        // 3. 从进程可执行文件提取默认图标
        TCHAR szExePath[MAX_PATH] = {0};
        DWORD pid = 0;
        GetWindowThreadProcessId(hWnd, &pid);
        
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
        if (hProcess) {
            GetModuleFileNameEx(hProcess, NULL, szExePath, MAX_PATH);
            CloseHandle(hProcess);
            
            ExtractIconEx(szExePath, 0, getLargeIcon ? &hIcon : NULL, getLargeIcon ? NULL : &hIcon, 1);
        }
    }

    return hIcon;
}

步骤2:将图标句柄转换为位图

得到图标句柄后,将其绘制到内存设备上下文(DC)中,生成位图对象。

C++ 示例代码

HBITMAP IconToBitmap(HICON hIcon, bool isLargeIcon) {
    if (!hIcon) return NULL;

    // 获取系统图标标准尺寸
    int cx = isLargeIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXSMICON);
    int cy = isLargeIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYSMICON);

    // 创建兼容DC和位图
    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(hdcScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, cx, cy);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);

    // 将图标绘制到内存DC
    DrawIconEx(hdcMem, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);

    // 清理资源
    SelectObject(hdcMem, hOldBitmap);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdcScreen);

    return hBitmap;
}

.NET (C#) 实现方案

如果使用C#开发,可通过P/Invoke调用Win32 API,将图标转换为.NET的Bitmap对象:

C# 示例代码

using System;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;

public static class WindowIconHelper
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex);

    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    private static extern uint ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);

    [DllImport("user32.dll")]
    private static extern bool DrawIconEx(IntPtr hdc, int xLeft, int yTop, IntPtr hIcon, int cxWidth, int cyHeight, int istepIfAniCur, IntPtr hbrFlickerFreeDraw, uint diFlags);

    [DllImport("user32.dll")]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll")]
    private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);

    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hObject);

    [DllImport("psapi.dll")]
    private static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize);

    [DllImport("gdi32.dll")]
    private static extern IntPtr CreateCompatibleDC(IntPtr hdc);

    [DllImport("gdi32.dll")]
    private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

    [DllImport("gdi32.dll")]
    private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

    [DllImport("gdi32.dll")]
    private static extern bool DeleteDC(IntPtr hdc);

    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);

    private const uint WM_GETICON = 0x007F;
    private const int ICON_BIG = 1;
    private const int ICON_SMALL = 0;
    private const int GCLP_HICON = -14;
    private const int GCLP_HICONSM = -34;
    private const uint DI_NORMAL = 0x0003;
    private const uint PROCESS_QUERY_INFORMATION = 0x0400;
    private const uint PROCESS_VM_READ = 0x0010;

    public static Bitmap GetWindowBitmap(IntPtr hWnd, bool largeIcon = true)
    {
        // 获取图标句柄
        IntPtr hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)(largeIcon ? ICON_BIG : ICON_SMALL), IntPtr.Zero);
        
        if (hIcon == IntPtr.Zero)
            hIcon = GetClassLongPtr(hWnd, largeIcon ? GCLP_HICON : GCLP_HICONSM);
        
        if (hIcon == IntPtr.Zero)
        {
            uint pid = 0;
            GetWindowThreadProcessId(hWnd, out pid);
            IntPtr hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
            
            if (hProcess != IntPtr.Zero)
            {
                StringBuilder sb = new StringBuilder(260);
                GetModuleFileNameEx(hProcess, IntPtr.Zero, sb, (uint)sb.Capacity);
                CloseHandle(hProcess);
                
                IntPtr[] icons = new IntPtr[1];
                ExtractIconEx(sb.ToString(), 0, largeIcon ? icons : null, largeIcon ? null : icons, 1);
                hIcon = icons[0];
            }
        }

        if (hIcon == IntPtr.Zero) return null;

        // 转换为Bitmap
        int cx = largeIcon ? SystemInformation.IconSize.Width : SystemInformation.SmallIconSize.Width;
        int cy = largeIcon ? SystemInformation.IconSize.Height : SystemInformation.SmallIconSize.Height;

        using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
        {
            IntPtr hdc = g.GetHdc();
            IntPtr hdcMem = CreateCompatibleDC(hdc);
            IntPtr hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
            IntPtr hOldBitmap = SelectObject(hdcMem, hBitmap);

            DrawIconEx(hdcMem, 0, 0, hIcon, cx, cy, 0, IntPtr.Zero, DI_NORMAL);

            SelectObject(hdcMem, hOldBitmap);
            DeleteDC(hdcMem);
            g.ReleaseHdc(hdc);

            Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);
            DeleteObject(hBitmap);
            return bitmap;
        }
    }
}

关键注意事项

  • 资源释放:所有通过Win32 API获取的句柄(HICON、HBITMAP、HDC等)必须调用对应销毁函数(DestroyIcon、DeleteObject、DeleteDC)释放,避免内存泄漏。
  • 权限问题:若目标进程以高权限运行,你的应用需要拥有同等或更高权限才能成功读取进程信息。
  • 动态图标处理:部分窗口使用动态绘制的图标(而非标准图标资源),此时WM_GETICON可能返回空,可尝试用PrintWindow捕获窗口区域,但这并非专门获取图标的方法。

内容的提问来源于stack exchange,提问作者ivan.ukr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 01:45:08