用JNA检测HICON的大小

时间:2015-01-21 11:19:26

标签: java winapi jna

我的最终目标是在JNA库的帮助下获取Java中的HWND图标。一切正常,除了一件重要的事情:我需要图标的大小,以便在Java中进一步处理。

似乎我不能要求尺寸。我总是获得大小0x0。我究竟做错了什么?基本代码示例如下所示。大多数API函数模板不是JNA的一部分。所以,我必须自己定义它们。

    final long hicon = ExtUser32.INSTANCE.SendMessageA(hwnd, ExtUser32.WM_GETICON, ExtUser32.ICON_BIG, 0);
    final Pointer hIcon = new Pointer(hicon);
    final ICONINFO info = new ICONINFO();
    final BITMAP bmp = new BITMAP();
    final SIZE size = new SIZE();

    System.out.println(ExtUser32.INSTANCE.GetIconInfo(hIcon, info));
    System.out.println(info);
    System.out.println(ExtGdi32.INSTANCE.GetBitmapDimensionEx(info.hbmColor, size));
    System.out.println(size);

    if (info.hbmColor != null)
    {
        final int nWrittenBytes = ExtGdi32.INSTANCE.GetObjectA(info.hbmColor, bmp.size(), bmp.getPointer());
        System.out.println(nWrittenBytes);
        System.out.println(bmp);
    }

sysouts打印出来:

true
ICONINFO(auto-allocated@0x5b72b4f0 (32 bytes)) {
  WinDef$BOOL fIcon@0=1
  WinDef$DWORD xHotspot@4=16
  WinDef$DWORD yHotspot@8=16
  WinDef$HBITMAP hbmMask@10=native@0xffffffffb00515e8 (com.sun.jna.platform.win32.WinDef$HBITMAP@b00515e7)
  WinDef$HBITMAP hbmColor@18=native@0xffffffffa50515c8 (com.sun.jna.platform.win32.WinDef$HBITMAP@a50515c7)
}
true
WinUser$SIZE(auto-allocated@0x652a3000 (8 bytes)) {
  int cx@0=0
  int cy@4=0
}
32
BITMAP(auto-allocated@0x5b72b5b0 (32 bytes)) {
  WinDef$LONG bmType@0=0
  WinDef$LONG bmWidth@4=0
  WinDef$LONG bmHeight@8=0
  WinDef$LONG bmWidthBytes@c=0
  WinDef$WORD bmPlanes@10=0
  WinDef$WORD bmBitsPixel@12=0
  WinDef$LPVOID bmBits@18=0
}

ICONINFO结构的请求似乎是正确的。但是,如果我尝试通过hbmColor请求集合Gdi32.GetBitmapDimensionEx()结构组件的维度,则结构将保持初始化为零。通过hbmColorhbmMask建议采用此方法:

How to determine the size of an icon from a HICON?

更新1

添加了错误跟踪!

由于sysouts指示(true),所涉及的函数调用并未失败。

更新2

进一步观察:在Java中,这些重新创建的结构类型在实例化后用零初始化。我将SIZE和BITMAP中结构组件的初始值设置为偏离零的值。 GetBitmapDimensionEx将其设置为零。但是GetObjectA并没有修改结构!函数的返回结果表明写入了字节,但这不是真的!

        ...
        size.cx = 1;
        size.cy = 2;

        bmp.bmType.setValue(1);
        bmp.bmWidth.setValue(2);
        bmp.bmHeight.setValue(3);
        bmp.bmWidthBytes.setValue(4);
        bmp.bmPlanes.setValue(5);
        bmp.bmBitsPixel.setValue(6);
        bmp.bmBits.setValue(7);

        System.out.println(ExtGdi32.INSTANCE.GetBitmapDimensionEx(info.hbmColor, size));
        System.out.println(size);

        if (info.hbmColor != null)
        {
            final int nWrittenBytes = ExtGdi32.INSTANCE.GetObjectA(info.hbmColor, bmp.size(), bmp.getPointer());
            System.out.println(nWrittenBytes);
            System.out.println(bmp);
        }

结果:

true
WinUser$SIZE(auto-allocated@0x64fbcb20 (8 bytes)) {
  int cx@0=0
  int cy@4=0
}
32
BITMAP(auto-allocated@0x64fb91f0 (32 bytes)) {
  WinDef$LONG bmType@0=1
  WinDef$LONG bmWidth@4=2
  WinDef$LONG bmHeight@8=3
  WinDef$LONG bmWidthBytes@c=4
  WinDef$WORD bmPlanes@10=5
  WinDef$WORD bmBitsPixel@12=6
  WinDef$LPVOID bmBits@18=7
}

2 个答案:

答案 0 :(得分:1)

我会将此作为评论添加,但我的声誉太低了:

你没有展示你的BITMAP或GetObjectA定义,所以我猜不过 在你的行:

        final int nWrittenBytes = ExtGdi32.INSTANCE.GetObjectA(info.hbmColor, bmp.size(), bmp.getPointer());

之后你没有调用'bmp.read()'。

如果你看一下Struture.getPointer()

的javadoc

https://jna.java.net/javadoc/com/sun/jna/Structure.html

你看到你负责在调用使用getPointer()获得的指针的本机方法之前和之后调用Structure.write()和Structure.read()。在你的情况下,写作是多余的,但这是一个很好的做法。

要理解为什么这是必要的,请考虑您的BITMAP / bmp对象是一个生活在Java堆中的Java对象,它可以在垃圾回收期间移动。因此,getPointer()无法返回“真实”对象的真实地址。相反,它返回一个指向本机堆中单独的固定(不可移动)内存块的指针(块JNA分配并与您的Java对象关联。现在,您的getObjectA()例程会将其内容写入 >内存但JNA或java端的任何人都无法知道这是发生了什么。所以你需要调用read()来告诉JNA将原生端东西复制到Java对象。

答案 1 :(得分:0)

如果这只是一个32位应用程序:

您的BITMAP结构不正确。这是一个简单的C程序,可以打印BITMAP所有字段的预期偏移量及其总大小:

// 24 january 2015
#include <windows.h>
#include <stdio.h>
#include <stddef.h>

int main(void)
{
    printf("%d\n", sizeof (BITMAP));
#define O(f) printf("%s %x\n", #f, offsetof(BITMAP, f))
    O(bmType);
    O(bmWidth);
    O(bmHeight);
    O(bmWidthBytes);
    O(bmPlanes);
    O(bmBitsPixel);
    O(bmBits);
    return 0;
}

这就是我得到的(在葡萄酒中,使用MinGW-w64编译为32位程序):

24
bmType 0
bmWidth 4
bmHeight 8
bmWidthBytes c
bmPlanes 10
bmBitsPixel 12
bmBits 14

请注意,上面的Java输出具有BITMAP的不同大小和bmBits的不同偏移量。

BITMAP结构适用于64位应用程序。)

一般:

为什么GetObject()表明成功超出了我的范围。

我根本不认识JNA,所以我不知道该怎么办。 JNA不提供WinGDI$BITMAP吗?