【问题标题】:Docking a java application jna on windows在 windows 上对接一个 java 应用程序 jna
【发布时间】:2025-11-21 23:40:02
【问题描述】:

我正在尝试构建一个 Windows 可停靠应用程序,它保留屏幕的一部分以防止其他应用程序显示在该空间中。

我尝试过使用 JNI 和 JNA。上面的代码显示了我已经走了多远。

package jnadock;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.ShellAPI;
import com.sun.jna.platform.win32.ShellAPI.APPBARDATA;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;


public class JNADock {

private HWND hWndGlobal;
private final String frameTitle = "Dockable frame";

public interface Shell32 extends StdCallLibrary {

    final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
        private static final long serialVersionUID = 1L;

        {
            put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
            put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
        }
    };

    public Shell32 INSTANCE = (Shell32) Native.loadLibrary("Shell32", Shell32.class, WIN32API_OPTIONS);

    UINT_PTR SHAppBarMessage(DWORD dwMessage, APPBARDATA pData);

}

public interface User32 extends StdCallLibrary {

    final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
        private static final long serialVersionUID = 1L;

        {
            put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
            put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
        }
    };

    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, WIN32API_OPTIONS);

    boolean EnumWindows(WinUser.WNDENUMPROC lpEnumFunc, Pointer arg);

    int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);

    HWND FindWindowA(String winClass, String title);
}

public static void main(String[] args) {
    JNADock jna = new JNADock();
}

public JNADock() {
    JFrame frame = new JFrame(frameTitle);
    frame.setSize(600, 100);

    frame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e){
            appbarRemove();
        }
    });
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    appbarSetPos();


    final User32 user32 = User32.INSTANCE;

    hWndGlobal = user32.FindWindowA(null, frameTitle);

    appbarNew() ;
    appbarSetPos();
    frame.setLocation(0,0);
}

 private void appbarNew() {

    APPBARDATA data = new APPBARDATA.ByReference();
    data.cbSize.setValue(data.size());
    int WM_USER = 0x0400;
    data.hWnd = hWndGlobal;
    data.uCallbackMessage.setValue(WM_USER + 1);

    UINT_PTR result = Shell32.INSTANCE.SHAppBarMessage(new DWORD(ShellAPI.ABM_NEW), data);
    System.out.println("result: " + result);
}

private void appbarSetPos() {
    APPBARDATA data = new APPBARDATA.ByReference();
    data.cbSize.setValue(data.size());
    data.uEdge.setValue(ShellAPI.ABE_TOP);

    data.rc.top = 0;
    data.rc.left = 0;
    data.rc.bottom = 100;
    data.rc.top = 600;

    UINT_PTR result = Shell32.INSTANCE.SHAppBarMessage(new DWORD(ShellAPI.ABM_SETPOS), data);
    System.out.println("result: " + result);
}

private void appbarRemove(){
    APPBARDATA data = new APPBARDATA.ByReference();
    data.cbSize.setValue(data.size());
    int WM_USER = 0x0400;
    data.hWnd = hWndGlobal;
    data.uCallbackMessage.setValue(WM_USER + 1);

    UINT_PTR result = Shell32.INSTANCE.SHAppBarMessage(new DWORD(ShellAPI.ABM_REMOVE), data);
    System.out.println("result: " + result);
}
}

执行时,会显示框架,但不会打印错误或提示我做错了什么。

请注意,我刚开始使用 JNA,可能会犯新手错误。随意抽出来。

【问题讨论】:

  • 您的User32 库的初始化方式应与Shell32 相同。您可能会发现从 JNA 的 platform.jar 中提供的那些库的版本中简单地派生更容易。
  • @technomage 完成,但是当您说“仅从提供的那些库的版本中派生”时,我并没有关注您。再次原谅我在这个领域缺乏经验。
  • JNA 提供 Shell32、User32 等版本。在它的 platform.jar 包中。如果您从中派生库接口,则需要定义的接口方法更少。

标签: java jna dock shell32


【解决方案1】:

在调用SHAppBarMessage(ABM_SETPOS) 之前,您必须初始化一个调用SHAppBarMessage(ABM_NEW) 的新AppBar,如下所示。

 private void appbarNew() {

    APPBARDATA data = new APPBARDATA.ByReference();
    data.cbSize.setValue(data.size());
    int WM_USER = 0x0400;
    data.hWnd = hWndGlobal;
    data.uCallbackMessage.setValue(WM_USER + 1);

    UINT_PTR result = Shell32.INSTANCE.SHAppBarMessage(new DWORD(ShellAPI.ABM_NEW), data);
    System.out.println("result: " + result);

}

最后不要忘记删除调用SHAppBarMessage(ABM_REMOVE)的新AppBar


Related docs from Microsoft Dev Center

【讨论】:

  • 感谢您的提示,但仍无法按预期工作。我已经更新了代码。尝试 ABM_NEW 时我得到 0。
  • 我已经在这里发布了我已经成功测试过的代码 sn-p gist.github.com/681fb27eea39404e86c5.git - Win7(64bit) - Java6 - jna-platform 4.1.0
  • 非常感谢您的宝贵时间!