Docking a java application jna on windows

2019-05-23 01:04发布

I'm trying to build a Windows dockable application that reserves a section of the screen to prevent other applications from show in that space.

I have try using JNI and JNA. The code above shows how far I have got.

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);
}
}

When executed, the frame is shown but no error or hint of what I'm doing wrong is printed.

Note that I just started using JNA and I could be committing rookie mistakes. Feel free to smoke them out.

1条回答
霸刀☆藐视天下
2楼-- · 2019-05-23 01:10

Before you call SHAppBarMessage(ABM_SETPOS) you have to initialize a new AppBar calling SHAppBarMessage(ABM_NEW)as show below.

 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);

}

At the end don't forget to remove the new AppBar calling SHAppBarMessage(ABM_REMOVE)


Related docs from Microsoft Dev Center

查看更多
登录 后发表回答