Java 使用JNA实现GetMenuItemInfo的参数无效
我正在调用win32 API函数Java 使用JNA实现GetMenuItemInfo的参数无效,java,winapi,jna,Java,Winapi,Jna,我正在调用win32 API函数GetMenuItemInfo。当我调用函数I时,它返回false,并且Native.getLastError()返回87: 错误\u无效\u参数87(0x57)参数不正确。 我认为我的错误是在实现结构MenuItemInfoW时: @Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId",
GetMenuItemInfo
。当我调用函数I时,它返回false
,并且Native.getLastError()
返回87:
错误\u无效\u参数87(0x57)参数不正确。
我认为我的错误是在实现结构MenuItemInfoW时:
@Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public WinDef.ULONGByReference dwItemData;
public WString dwTypeData;
public int cch;
public Pointer hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
}
}
这是我调用函数的代码:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 256;
menuiteminfow.dwTypeData = new WString(String.join("", Collections.nCopies(256, " ")));
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(), 0, true, menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
我已经为你的提示编辑了我的代码,但是我得到了相同的错误87。这是我的新代码:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 0;
menuiteminfow.dwTypeData = Pointer.NULL;
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(),
new WinDef.UINT(0), new WinDef.BOOL(true), menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
这是我的结构的新版本:
@Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public BaseTSD.LONG_PTR dwItemData;
public Pointer dwTypeData;
public int cch;
public WinDef.HBITMAP hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
this.read();
}
}
感谢您的回复。您的结构映射可以改进 首先,
ULONG\u PTR
与WinDef.ULONGByReference
不同。ULONG_PTR
是一个指针大小的值,但它实际上并不指向任何东西
JNA有一个内置的BaseTSD.LONG\PTR
类型,您可以在这里使用它
虽然指针
在技术上适用于hbmpItem
和其他位图字段,但类型WinDef.HBITMAP
已在JNA中定义,因此您应该使用该映射
最后,也是导致错误的可能原因,dwTypeData
接收到一个字符串,但它是一个需要分配和填充的缓冲区。从文档中:
要检索MFT_STRING
类型的菜单项,首先通过将MENUITEMINFO
的dwTypeData
成员设置为NULL
然后调用GetMenuItemInfo
来查找字符串的大小。cch+1的值是所需的大小。然后分配此大小的缓冲区,将指向该缓冲区的指针放入dwTypeData
,递增cch
,然后再次调用GetMenuItemInfo
,用字符串填充缓冲区
因此,在本例中,您希望将指针映射到dwTypeData
,第一次调用该函数时将该指针设置为Pointer.NULL
,然后根据递增的cch
为其分配内存:
menuiteminfow.cch++;
// allocate 2 bytes per widechar
menuiteminfow.dwTypeData = new Memory(cch * 2);
在函数调用之后,您可以使用menuiteminfow.dwTypeData.getWideString()
从那里获取字符串。您的结构映射可以得到改进
首先,ULONG\u PTR
与WinDef.ULONGByReference
不同。ULONG_PTR
是一个指针大小的值,但它实际上并不指向任何东西
JNA有一个内置的BaseTSD.LONG\PTR
类型,您可以在这里使用它
虽然指针
在技术上适用于hbmpItem
和其他位图字段,但类型WinDef.HBITMAP
已在JNA中定义,因此您应该使用该映射
最后,也是导致错误的可能原因,dwTypeData
接收到一个字符串,但它是一个需要分配和填充的缓冲区。从文档中:
要检索MFT_STRING
类型的菜单项,首先通过将MENUITEMINFO
的dwTypeData
成员设置为NULL
然后调用GetMenuItemInfo
来查找字符串的大小。cch+1的值是所需的大小。然后分配此大小的缓冲区,将指向该缓冲区的指针放入dwTypeData
,递增cch
,然后再次调用GetMenuItemInfo
,用字符串填充缓冲区
因此,在本例中,您希望将指针映射到dwTypeData
,第一次调用该函数时将该指针设置为Pointer.NULL
,然后根据递增的cch
为其分配内存:
menuiteminfow.cch++;
// allocate 2 bytes per widechar
menuiteminfow.dwTypeData = new Memory(cch * 2);
在函数调用之后,您可以使用menuiteminfow.dwTypeData.getWideString()
从那里获取字符串,而不管LONG
在Windows上是32位宽,而ULONG\u PTR
始终是指针大小。此外,无论dwItemData
中的dw
前缀是什么,都允许(实际上是常用的)此成员存储指向任意用户定义数据的指针。@IInspectable谢谢。每次我在回答中提到那种类型,我都会把事情搞砸。你可能认为我现在已经学会了。不管事实是什么,LONG
在Windows上是32位宽,而ULONG\u PTR
总是指针大小。此外,无论dwItemData
中的dw
前缀是什么,都允许(实际上是常用的)此成员存储指向任意用户定义数据的指针。@IInspectable谢谢。每次我在回答中提到那种类型,我都会把事情搞砸。你会认为我现在已经学会了。