有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

非常感谢this answer(以及其他许多人!)的《装满鳗鱼的气垫船》这构成了测试应用程序的基础

以下是我的问题:

  1. 图像绘制-我从窗口图标获得的图像以黑白绘制。我修改了McDowell从this answer开始的getImageForWindow中的代码(谢谢!)。有没有更好的方法将HICON对象转换为java。awt。形象我注意到com中有一个名为“fromNative”的方法。太阳jna。站台win32。W32API。但我不知道怎么用它

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

  3. 根据Alt选项卡弹出窗口获取正确的窗口列表-我试图复制在this C++ answer中所做的操作,但我无法在Java中实现第二个(get祖先等)和第三个(状态系统不可见)检查。我使用了一个糟糕的替代方法,即排除标题为空的窗口(忽略一些合法窗口)

注意:运行此示例需要JNA和平台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;
    }
}

共 (2) 个答案

  1. # 1 楼答案

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

    此解决方案基于this SO answer by aleroot。我获取进程文件路径(用于打开窗口的exe文件,与其他窗口详细信息一起存储在WindowInfo对象中),然后使用ShellFolder获取与该文件关联的图标注意:这并不总是给出正确的图标(例如,用于运行Netbeans进程的文件是java.exe,因此您得到的是java图标,而不是Netbeans图标!)。但在大多数情况下,它工作得很好

    解决问题1&;但如果有人有更好的解决方案,请告诉我。我在第三个问题上没有取得任何进展,但是我现在要做的是窗口列表

    这是我的更新代码。。。 注意:运行此示例需要JNA和平台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;
        }
    }
    
  2. # 2 楼答案

    丑陋的方法

    ShellFolder sf = ShellFolder.getShellFolder(new File("."));
    Method m = sf.getClass().getDeclaredMethod("makeIcon", Long.TYPE, Boolean.TYPE);
    m.setAccessible(true);
    Image image = (Image) m.invoke(null, Long.valueOf(iconHandle), Boolean.TRUE);