Java 使用JNA实现GetMenuItemInfo的参数无效

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",

我正在调用win32 API函数
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谢谢。每次我在回答中提到那种类型,我都会把事情搞砸。你会认为我现在已经学会了。