Java - 使用 JNA 的 Windows 任务栏 - 如何将窗口图标 (HICON) 转换为 java 图像?

2024-05-23

我正在尝试将应用程序切换器添加到我正在处理的更大项目中。它需要在 Windows XP/Vista/7/8 上运行。我正在使用 Java 1.7。下面是我创建的一个示例应用程序,用于演示我遇到的一些问题。我对 JNA 很陌生。

非常感谢“充满鳗鱼的气垫船”这个答案 https://stackoverflow.com/a/4478957/1678593(以及许多其他!)这构成了测试应用程序的基础。

这是我的问题:

  1. 图像绘制- 我从窗口图标获得的图像是黑白绘制的。我修改了 getImageForWindow 中的代码这个答案 https://stackoverflow.com/a/740528/1678593作者:麦克道尔(谢谢!)。有没有更好的方法将 HICON 对象转换为 java.awt.Image?我注意到 com.sun.jna.platform.win32.W32API.HICON 中有一个名为“fromNative”的方法,但我不知道如何使用它。

  2. 获取图标- 我用来获取图标句柄的调用 GetClassLongW(hWnd, GCL_HICON) 不会从 64 位窗口返回图标。我想我需要 GetClassLongPtr 来实现这一点,但我似乎无法通过 JNA 访问它。

  3. 根据 Alt-tab 弹出窗口获取正确的窗口列表- 我试图复制所做的事情这个 C++ 答案 https://stackoverflow.com/a/7292674/1678593但我无法设法在 Java 中实现第二个(GetAncestor 等)和第三个(STATE_SYSTEM_INVISIBLE)检查。我正在使用一个糟糕的替代品,即排除标题为空白的窗口(它忽略一些合法的窗口)。

Note:运行此示例需要 JNA 和 Platform jar:

    package test;

import static test.WindowSwitcher.User32DLL.*;
import static test.WindowSwitcher.Gdi32DLL.*;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class WindowSwitcher
{
    public static void main(String args[])
    {
        JFrame JF = new JFrame();
        JPanel JP = new JPanel(new GridLayout(0, 1));

        JF.getContentPane().add(JP);

        Vector<WindowInfo> V = getActiveWindows();
        for (int i = 0; i < V.size(); i++)
        {
            final WindowInfo WI = V.elementAt(i);
            JButton JB = new JButton(WI.title);

            if(WI.image != null)
            {
                JB.setIcon(new ImageIcon(WI.image));
            }

            JB.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    SetForegroundWindow(WI.hWnd);
                }
            });

            JP.add(JB);
        }

        JF.setSize(600,50+V.size()*64);
        JF.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JF.setAlwaysOnTop(true);
        JF.setFocusableWindowState(false);
        JF.setVisible(true);
    }

    public static Vector<WindowInfo> getActiveWindows()
    {
        final Vector<WindowInfo> V = new Vector();

        EnumWindows(new WNDENUMPROC()
        {
            public boolean callback(Pointer hWndPointer, Pointer userData)
            {
                HWND hWnd = new HWND(hWndPointer);

                // Make sure the window is visible
                if(IsWindowVisible(hWndPointer))
                {
                    int GWL_EXSTYLE = -20;
                    long WS_EX_TOOLWINDOW = 0x00000080L;

                    // Make sure this is not a tool window
                    if((GetWindowLongW(hWndPointer, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) == 0)
                    {
                        // Get the title bar text for the window
                        char[] windowText = new char[512];
                        GetWindowTextW(hWnd, windowText, windowText.length);
                        String wText = Native.toString(windowText);

                        // Make sure the text is not null or blank
                        if(!(wText == null || wText.trim().equals("")))
                        {
                            // Get the icon image for the window (if available)
                            Image image = getImageForWindow(hWnd, wText);

                            // This window is a valid taskbar button, add a WindowInfo object to the return vector
                            V.add(new WindowInfo(wText, hWnd, image));
                        }
                    }
                }

                return true;
            }
        }, null);

        return V;
    }

    public static Image getImageForWindow(HWND hWnd, String wText)
    {
        // Get an image from the icon for this window
        int hicon = GetClassLongW(hWnd, GCL_HICON);

        if(hicon == 0)
            return null;

        Pointer hIcon = new Pointer(hicon);

        int width = 64;
        int height = 64;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        draw(image, hIcon, DI_NORMAL);
        BufferedImage mask = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        draw(mask, hIcon, DI_MASK);
        applyMask(image, mask);

        return image;
    }
    public static void draw(BufferedImage image, Pointer hIcon, int diFlags)
    {
        int width = image.getWidth();
        int height = image.getHeight();

        Pointer hdc = CreateCompatibleDC(Pointer.NULL);
        Pointer bitmap = CreateCompatibleBitmap(hdc, width, height);

        SelectObject(hdc, bitmap);
        DrawIconEx(hdc, 0, 0, hIcon, width, height, 0, Pointer.NULL, diFlags);

        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < width; y++)
            {
                int rgb = GetPixel(hdc, x, y);
                image.setRGB(x, y, rgb);
            }
        }

        DeleteObject(bitmap);
        DeleteDC(hdc);
    }
    private static void applyMask(BufferedImage image,
            BufferedImage mask)
    {
        int width = image.getWidth();
        int height = image.getHeight();
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                int masked = mask.getRGB(x, y);
                if ((masked & 0x00FFFFFF) == 0)
                {
                    int rgb = image.getRGB(x, y);
                    rgb = 0xFF000000 | rgb;
                    image.setRGB(x, y, rgb);
                }
            }
        }
    }

    static class User32DLL
    {
        static
        {
            Native.register("user32");
        }

        public static native int GetWindowTextW(HWND hWnd, char[] lpString, int nMaxCount);

        public static native boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);

        public static interface WNDENUMPROC extends com.sun.jna.win32.StdCallLibrary.StdCallCallback
        {
            boolean callback(Pointer hWnd, Pointer arg);
        }

        public static native boolean IsWindowVisible(Pointer hWnd);

        public static native boolean SetForegroundWindow(HWND hWnd);

        public static native int GetWindowLongW(Pointer hWnd, int nIndex);

        public static int GCL_HICON = -14;
        public static int GCL_HICONSM = -34;
        public static native int GetClassLongW(HWND hWnd, int nIndex);

        /** @see #DrawIconEx(Pointer, int, int, Pointer, int, int, int, Pointer, int) */
        public static final int DI_COMPAT = 4;
        public static final int DI_DEFAULTSIZE = 8;
        public static final int DI_IMAGE = 2;
        public static final int DI_MASK = 1;
        public static final int DI_NORMAL = 3;
        public static final int DI_APPBANDING = 1;

        /** http://msdn.microsoft.com/en-us/library/ms648065(VS.85).aspx */
        public static native boolean DrawIconEx(Pointer hdc, int xLeft,
                int yTop, Pointer hIcon, int cxWidth, int cyWidth,
                int istepIfAniCur, Pointer hbrFlickerFreeDraw,
                int diFlags);
    }

    static class Gdi32DLL
    {
        static
        {
            Native.register("gdi32");
        }

        /** http://msdn.microsoft.com/en-us/library/dd183489(VS.85).aspx */
        public static native Pointer CreateCompatibleDC(Pointer hdc);

        /** http://msdn.microsoft.com/en-us/library/dd183488(VS.85).aspx */
        public static native Pointer CreateCompatibleBitmap(Pointer hdc, int nWidth, int nHeight);

        /** http://msdn.microsoft.com/en-us/library/dd162957(VS.85).aspx */
        public static native Pointer SelectObject(Pointer hdc, Pointer hgdiobj);

        /** http://msdn.microsoft.com/en-us/library/dd145078(VS.85).aspx */
        public static native int SetPixel(Pointer hdc, int X, int Y, int crColor);

        /** http://msdn.microsoft.com/en-us/library/dd144909(VS.85).aspx */
        public static native int GetPixel(Pointer hdc, int nXPos, int nYPos);

        /** http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx */
        public static native boolean DeleteObject(Pointer hObject);

        /** http://msdn.microsoft.com/en-us/library/dd183533(VS.85).aspx */
        public static native boolean DeleteDC(Pointer hdc);
    }
}
class WindowInfo
{
    String title;
    HWND hWnd;
    Image image;

    public WindowInfo(String title, HWND hWnd, Image image)
    {
        this.title = title;
        this.hWnd = hWnd;
        this.image = image;
    }
}

我找到了一种可以满足我的目的的解决方法。这比我第一次尝试要简单得多!我现在使用 sun.awt.shell.ShellFolder 获取图标,不幸的是,这是一个未记录/不受支持的类,可能会在未来的 Java 版本中删除。还有另一种方法可以使用 FileSystemView 获取图标,但返回的图标对于我的目的来说太小(在下面的示例中注释掉了 - getImageForWindowIcon 方法)。

此解决方法基于aleroot 的这个答案 https://stackoverflow.com/a/10693205/1678593。我获取进程文件路径(用于打开窗口的 exe 文件,我将其与其他窗口详细信息一起存储在 WindowInfo 对象中),然后使用 ShellFolder 获取与该文件关联的图标。Note:这并不总是给出正确的图标(例如,用于运行 Netbeans 进程的文件是 java.exe,因此您得到的是 Java 图标,而不是 Netbeans 图标!)。但在大多数情况下,它运作良好!

该解决方法解决了上述问题 1 和 2,但如果有人有更好的解决方案,请告诉我。我对问题 3 没有任何进展,但我现在必须做的窗口列表。

这是我更新的代码...Note:运行此示例需要 JNA 和 Platform jar:

    package test;

import static test.WindowSwitcher.User32DLL.*;
import static test.WindowSwitcher.Kernel32.*;
import static test.WindowSwitcher.Psapi.*;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.ptr.PointerByReference;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import sun.awt.shell.ShellFolder;

public class WindowSwitcher
{
    public static void main(String args[])
    {
        new WindowSwitcher();
    }
    public WindowSwitcher()
    {
        JFrame JF = new JFrame("Window Switcher");
        JPanel JP = new JPanel(new GridLayout(0, 1));

        JF.getContentPane().add(JP);

        Vector<WindowInfo> V = getActiveWindows();
        for (int i = 0; i < V.size(); i++)
        {
            final WindowInfo WI = V.elementAt(i);
            JButton JB = new JButton(WI.title);

            if(WI.image != null)
            {
                JB.setIcon(new ImageIcon(WI.image));
            }

            JB.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    SetForegroundWindow(WI.hWnd);
                }
            });

            JP.add(JB);
        }

        JF.setSize(600,50+V.size()*64);
        JF.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JF.setAlwaysOnTop(true);
        JF.setFocusableWindowState(false);
        JF.setVisible(true);
    }

    private Vector<WindowInfo> getActiveWindows()
    {
        final Vector<WindowInfo> V = new Vector();

        EnumWindows(new WNDENUMPROC()
        {
            public boolean callback(Pointer hWndPointer, Pointer userData)
            {
                HWND hWnd = new HWND(hWndPointer);

                // Make sure the window is visible
                if(IsWindowVisible(hWndPointer))
                {
                    int GWL_EXSTYLE = -20;
                    long WS_EX_TOOLWINDOW = 0x00000080L;

                    // Make sure this is not a tool window
                    if((GetWindowLongW(hWndPointer, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) == 0)
                    {
                        // Get the title bar text for the window (and other info)
                        WindowInfo info = getWindowTitleAndProcessDetails(hWnd);

                        // Make sure the text is not null or blank
                        if(!(info.title == null || info.title.trim().equals("")))
                        {
                            // Get the icon image for the window (if available)
                            info.image = getImageForWindow(info);

                            // This window is a valid taskbar button, add a WindowInfo object to the return vector
                            V.add(info);
                        }
                    }
                }

                return true;
            }
        }, null);

        return V;
    }

    private static final int MAX_TITLE_LENGTH = 1024;
    private WindowInfo getWindowTitleAndProcessDetails(HWND hWnd)
    {
        if(hWnd == null)
            return null;

        char[] buffer = new char[MAX_TITLE_LENGTH * 2];
        GetWindowTextW(hWnd, buffer, MAX_TITLE_LENGTH);
        String title = Native.toString(buffer);

        PointerByReference pointer = new PointerByReference();
        GetWindowThreadProcessId(hWnd, pointer);    //GetForegroundWindow()
        Pointer process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pointer.getValue());
        GetModuleBaseNameW(process, null, buffer, MAX_TITLE_LENGTH);
        String Sprocess = Native.toString(buffer);
        GetModuleFileNameExW(process, null, buffer, MAX_TITLE_LENGTH);
        String SprocessFilePath = Native.toString(buffer);

        return new WindowInfo(title, Sprocess, SprocessFilePath, hWnd, null);
    }

    private Image getImageForWindow(WindowInfo info)
    {
        if(info.processFilePath == null || info.processFilePath.trim().equals(""))
            return null;

        try
        {
            File f = new File(info.processFilePath);

            if(f.exists())
            {
                // https://stackoverflow.com/questions/10693171/how-to-get-the-icon-of-another-application
                // http://www.rgagnon.com/javadetails/java-0439.html
                ShellFolder sf = ShellFolder.getShellFolder(f);
                if(sf != null)
                    return sf.getIcon(true);

                // Image returned using this method is too small!
                //Icon icon = FileSystemView.getFileSystemView().getSystemIcon(f);
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    static class Psapi
    {
        static
        {
            Native.register("psapi");
        }

        public static native int GetModuleBaseNameW(Pointer hProcess, Pointer hmodule, char[] lpBaseName, int size);

        public static native int GetModuleFileNameExW(Pointer hProcess, Pointer hmodule, char[] lpBaseName, int size);
    }

    static class Kernel32
    {

        static
        {
            Native.register("kernel32");
        }
        public static int PROCESS_QUERY_INFORMATION = 0x0400;
        public static int PROCESS_VM_READ = 0x0010;

        public static native Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer);
    }

    static class User32DLL
    {
        static
        {
            Native.register("user32");
        }

        public static native int GetWindowThreadProcessId(HWND hWnd, PointerByReference pref);

        public static native int GetWindowTextW(HWND hWnd, char[] lpString, int nMaxCount);

        public static native boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);

        public static interface WNDENUMPROC extends com.sun.jna.win32.StdCallLibrary.StdCallCallback
        {
            boolean callback(Pointer hWnd, Pointer arg);
        }

        public static native boolean IsWindowVisible(Pointer hWnd);

        public static native boolean SetForegroundWindow(HWND hWnd);

        public static native int GetWindowLongW(Pointer hWnd, int nIndex);
    }
}
class WindowInfo
{
    String title, process, processFilePath;
    HWND hWnd;
    Image image;

    public WindowInfo(String title, String process, String processFilePath, HWND hWnd, Image image)
    {
        this.title = title;
        this.process = process;
        this.processFilePath = processFilePath;
        this.hWnd = hWnd;
        this.image = image;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java - 使用 JNA 的 Windows 任务栏 - 如何将窗口图标 (HICON) 转换为 java 图像? 的相关文章

随机推荐

  • WPF:动画不流畅

    我正在制作一个动画TextBlock 60秒后增加FontSize从 8 点到 200 点 一切工作正常 除了我的动画随着文本的增长而上下移动 为什么会发生这种情况 是否可以避免这种情况 我有一个非常简单的 XAML 文件
  • 程序不等待 cin

    int x 0 string fullname float salary float payincrease float newsal float monthlysal float retroactive while x lt 3 cout
  • 什么是多维 OLAP CUBE 并给出超过 3 维的多维数据集示例

    由于我是 SSAS 的新手 一直在阅读有关多维 OLAP 多维数据集的文章 并努力理解多维数据集的概念 据说虽然术语 多维数据集 表示三个维度 但多维数据集最多可以有 64 个维度 你能解释一下这在立方体上怎么可能吗 除了 3 Dim 示例
  • 无法在 Perl 中找到 DBI.pm 模块

    我使用的是 CentOS 并且已经安装了 Perl 5 20 并且默认情况下存在 Perl 5 10 我正在使用 Perl 5 20 版本来执行 Perl 代码 我尝试使用 DBI 模块并收到此错误 root localhost perl
  • Facebook“赞”按钮回调帮助

    我正在使用此代码进行类似 facebook 的回调 问题是 如果我调用 php 脚本 例如 有人可以看到我的 javascript 并运行此页面 甚至可以向其发送垃圾邮件或在没有先点赞的情况下使用它 我的想法是 我想为每个喜欢该页面的用户提
  • 如何将对象数组传递给活动?

    我读过有关从活动传递数组和向活动传递数组的帖子 但我对如何针对我的具体情况执行此操作感到困惑 我有一个名为 DaysWeather 的对象数组 DaysWeather 数组 其中对象具有多个字符串属性以及位图属性 我在某处读到 你必须使其可
  • 聚合物在核心输入上使用功能验证

    有人可以解释一下如何使用函数验证吗这种聚合物元素 http www polymer project org docs elements core elements html core input 导航到 验证 部分
  • 如何在java中的itext pdf库中为段落添加边框?

    我在java中使用itext pdf库创建了一个段落 我必须为段落添加边框 而不是为整个文档添加边框 怎么做 请看一下段落边框 http itextpdf com sandbox events BorderForParagraph例子 它展
  • python 父子关系类

    我写了一个类 如下所示 我想添加 的属性parent 到我的基类 Node 我想知道是否有人可以告诉我如何正确地做到这一点 我已经得到了如何做到这一点的指导 但我不完全确定如何明智地编写它 这是建议的方法 通常我会将父属性隐藏在属性后面 所
  • Jqgrid获取我们输入的值并更改表单的可编辑属性

    对不起 伙计们 但我遇到了这两个问题 我希望你们能帮我解决这个问题 这是我的代码的一部分 jQuery VWWMODULE jqGrid url loadstatic php q 2 t CORE VW WMODULE datatype j
  • value >= all(select v2 ...) 产生与 value = (select max(v2) ...) 不同的结果

    Here https stackoverflow com questions 17026651 query from union of joins 17027784 noredirect 1 comment24611997 17027784
  • 替换主窗口中的 CentralWidget

    我对 PySide 有点陌生 我有一个主窗口对象 一次显示一个小部件 我一直在尝试更改中央小部件QMainWindow类 以便在按下按钮时替换窗口中可见的小部件 问题是按下的按钮是在 Widget 类中 而不是在主窗口类中 say clas
  • 为什么我在 python 中的 Spearman 相关性中得到 nan

    我在用scipy来计算相关性 我计算斯皮尔曼相关性的代码如下 from scipy import stats sequence 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 sequence 2 0 0
  • 是否可以获取绑定到 jQuery 元素的事件列表?

    正如问题所说 我需要绑定到特定元素的事件列表 我的意思是像单击 鼠标悬停等事件在 dom 加载时绑定到该元素 愚蠢 示例 element click function stuff element mouseover function stu
  • Jenkins Hash 的 Python 实现?

    是否存在该方法的原生 Python 实现詹金斯哈希 http burtleburtle net bob hash doobs html算法 我需要一个哈希算法 它接受任意字符串并将其转换为 32 位整数 对于给定的字符串 必须保证跨平台返回
  • Google 跟踪代码管理器导致 SPA 中的整个页面重新加载 - React

    当我在 React 的 GTM 中添加触发器时 a a or 元素 它会导致单击时重新加载整个页面 而不是仅重新渲染应用程序的一部分 当我删除谷歌跟踪时 一切都会顺利进行 有没有办法 如何配置 GTM 不影响应用程序的行为 如果 Googl
  • 使用 importlib 加载已编译的模块

    从 Python 3 4 开始 模块 imp 已被弃用 使得imp load compiled modname modpath 不鼓励的加载字节码的机制 有没有一种简单的方法可以使用 importlib 加载已编译的模块 我正在向学生提供一
  • OpenStreetMap 不显示在 RStudio 中(使用 R 3.2.1)

    我正在使用来自的代码here https rstudio github io leaflet library leaflet m lt leaflet gt addTiles gt addMarkers lng 174 768 lat 36
  • 如何读取rack请求中的POST数据

    当我运行curl命令时 curl v H Content type application json X POST d name abc id 12 subject my subject http localhost 9292 要将包含数据
  • Java - 使用 JNA 的 Windows 任务栏 - 如何将窗口图标 (HICON) 转换为 java 图像?

    我正在尝试将应用程序切换器添加到我正在处理的更大项目中 它需要在 Windows XP Vista 7 8 上运行 我正在使用 Java 1 7 下面是我创建的一个示例应用程序 用于演示我遇到的一些问题 我对 JNA 很陌生 非常感谢 充满