Java JNA Write Custom COM Interface of win32 API
Java JNA Write Custom COM Interface of win32 API
我需要编写 win32 的自定义 IShellFolder 接口 API。但是我在调用方法 ParseDisplayName 时遇到问题。 jna 的原始版本有一个错误,此方法的 pszDisplayName 参数是 String 但 win32 api 具有 wstring 作为参数。
这是我的代码
String file = "c:\Users\Duchon\Downloads\Baumüller Brno, s.r.o.PS43668.prpkg";
PointerByReference psfDesktopPTR = new PointerByReference();
WinNT.HRESULT hResult = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR);
if (COMUtils.SUCCEEDED(hResult)) {
IntByReference pcheaten = new IntByReference();
PointerByReference ppidl = new PointerByReference();
IntByReference pdwAttributes = new IntByReference();
IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR);
hResult = psfDesktop.ParseDisplayName(null, null, new WString(file), pcheaten, ppidl, pdwAttributes);
if (COMUtils.SUCCEEDED(hResult)) {
}
}
这是我的 IShellFolder 界面:
public interface IShellFolder {
WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes);
public static class Converter {
public static IShellFolder PointerToIShellFolder(final PointerByReference ptr) {
final Pointer interfacePointer = ptr.getValue();
final Pointer vTablePointer = interfacePointer.getPointer(0);
final Pointer[] vTable = new Pointer[1];
vTablePointer.read(0, vTable, 0, 1);
return new IShellFolder() {
@Override
public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] {interfacePointer, hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes }));
}
};
}
}
}
并调用方法 ParseDisplay 抛出异常java.lang.Error:无效的内存访问。
遇到错误你能帮帮我吗
非常感谢。
你快到了。通常自定义现有 JNA 接口的方法是定义您自己的扩展它的接口,然后编写您自己的方法。对于单一方法,您基本上已经完成,但是 Converter
class 生成一个匿名的 class,您需要完全复制它。这应该有效。
public interface MyIShellFolder extends com.sun.jna.platform.win32.COM.IShellFolder {
// Define your own function invocation.
// Since your argument signature includes a WString
// it will be an overloaded version selected when you use the
// WString argument.
WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten,
PointerByReference ppidl, IntByReference pdwAttributes);
// Do the same extending the inner class
public static class Converter extends com.sun.jna.platform.win32.COM.IShellFolder.Converter {
// You are overriding the superclass version of this so you have
// to define the entire method
public static MyIShellFolder PointerToIShellFolder(final PointerByReference ptr) {
final Pointer interfacePointer = ptr.getValue();
final Pointer vTablePointer = interfacePointer.getPointer(0);
final Pointer[] vTable = new Pointer[13];
vTablePointer.read(0, vTable, 0, 13);
return new MyIShellFolder() {
@Override
public WinNT.HRESULT QueryInterface(REFIID byValue, PointerByReference pointerByReference) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, byValue, pointerByReference }));
}
@Override
public int AddRef() {
Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION);
return f.invokeInt(new Object[] { interfacePointer });
}
public int Release() {
Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
return f.invokeInt(new Object[] { interfacePointer });
}
@Override
public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName,
IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
Function f = Function.getFunction(vTable[3], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwnd, pbc, pszDisplayName,
pchEaten, ppidl, pdwAttributes }));
}
@Override
public WinNT.HRESULT EnumObjects(WinDef.HWND hwnd, int grfFlags, PointerByReference ppenumIDList) {
Function f = Function.getFunction(vTable[4], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, hwnd, grfFlags, ppenumIDList }));
}
public WinNT.HRESULT BindToObject(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[5], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
}
@Override
public HRESULT BindToStorage(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[6], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
}
@Override
public HRESULT CompareIDs(WinDef.LPARAM lParam, Pointer pidl1, Pointer pidl2) {
Function f = Function.getFunction(vTable[7], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, lParam, pidl1, pidl2 }));
}
@Override
public HRESULT CreateViewObject(WinDef.HWND hwndOwner, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[8], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwndOwner, riid, ppv }));
}
@Override
public HRESULT GetAttributesOf(int cidl, Pointer apidl, IntByReference rgfInOut) {
Function f = Function.getFunction(vTable[9], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, cidl, apidl, rgfInOut }));
}
@Override
public HRESULT GetUIObjectOf(WinDef.HWND hwndOwner, int cidl, Pointer apidl, REFIID riid,
IntByReference rgfReserved, PointerByReference ppv) {
Function f = Function.getFunction(vTable[10], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(
new Object[] { interfacePointer, hwndOwner, cidl, apidl, riid, rgfReserved, ppv }));
}
public WinNT.HRESULT GetDisplayNameOf(Pointer pidl, int flags, STRRET pName) {
Function f = Function.getFunction(vTable[11], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, flags, pName }));
}
@Override
public HRESULT SetNameOf(WinDef.HWND hwnd, Pointer pidl, String pszName, int uFlags,
PointerByReference ppidlOut) {
Function f = Function.getFunction(vTable[12], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, hwnd, pidl, pszName, uFlags, ppidlOut }));
}
// OLD VERSION THAT YOU WANT TO IGNORE BUT MUST DECLARE
@Override
public HRESULT ParseDisplayName(HWND hwnd, Pointer pbc, String pszDisplayName, IntByReference pchEaten,
PointerByReference ppidl, IntByReference pdwAttributes) {
return null;
}
};
}
}
}
我需要编写 win32 的自定义 IShellFolder 接口 API。但是我在调用方法 ParseDisplayName 时遇到问题。 jna 的原始版本有一个错误,此方法的 pszDisplayName 参数是 String 但 win32 api 具有 wstring 作为参数。
这是我的代码
String file = "c:\Users\Duchon\Downloads\Baumüller Brno, s.r.o.PS43668.prpkg";
PointerByReference psfDesktopPTR = new PointerByReference();
WinNT.HRESULT hResult = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR);
if (COMUtils.SUCCEEDED(hResult)) {
IntByReference pcheaten = new IntByReference();
PointerByReference ppidl = new PointerByReference();
IntByReference pdwAttributes = new IntByReference();
IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR);
hResult = psfDesktop.ParseDisplayName(null, null, new WString(file), pcheaten, ppidl, pdwAttributes);
if (COMUtils.SUCCEEDED(hResult)) {
}
}
这是我的 IShellFolder 界面:
public interface IShellFolder {
WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes);
public static class Converter {
public static IShellFolder PointerToIShellFolder(final PointerByReference ptr) {
final Pointer interfacePointer = ptr.getValue();
final Pointer vTablePointer = interfacePointer.getPointer(0);
final Pointer[] vTable = new Pointer[1];
vTablePointer.read(0, vTable, 0, 1);
return new IShellFolder() {
@Override
public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] {interfacePointer, hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes }));
}
};
}
}
}
并调用方法 ParseDisplay 抛出异常java.lang.Error:无效的内存访问。
遇到错误你能帮帮我吗
非常感谢。
你快到了。通常自定义现有 JNA 接口的方法是定义您自己的扩展它的接口,然后编写您自己的方法。对于单一方法,您基本上已经完成,但是 Converter
class 生成一个匿名的 class,您需要完全复制它。这应该有效。
public interface MyIShellFolder extends com.sun.jna.platform.win32.COM.IShellFolder {
// Define your own function invocation.
// Since your argument signature includes a WString
// it will be an overloaded version selected when you use the
// WString argument.
WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten,
PointerByReference ppidl, IntByReference pdwAttributes);
// Do the same extending the inner class
public static class Converter extends com.sun.jna.platform.win32.COM.IShellFolder.Converter {
// You are overriding the superclass version of this so you have
// to define the entire method
public static MyIShellFolder PointerToIShellFolder(final PointerByReference ptr) {
final Pointer interfacePointer = ptr.getValue();
final Pointer vTablePointer = interfacePointer.getPointer(0);
final Pointer[] vTable = new Pointer[13];
vTablePointer.read(0, vTable, 0, 13);
return new MyIShellFolder() {
@Override
public WinNT.HRESULT QueryInterface(REFIID byValue, PointerByReference pointerByReference) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, byValue, pointerByReference }));
}
@Override
public int AddRef() {
Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION);
return f.invokeInt(new Object[] { interfacePointer });
}
public int Release() {
Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
return f.invokeInt(new Object[] { interfacePointer });
}
@Override
public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName,
IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
Function f = Function.getFunction(vTable[3], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwnd, pbc, pszDisplayName,
pchEaten, ppidl, pdwAttributes }));
}
@Override
public WinNT.HRESULT EnumObjects(WinDef.HWND hwnd, int grfFlags, PointerByReference ppenumIDList) {
Function f = Function.getFunction(vTable[4], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, hwnd, grfFlags, ppenumIDList }));
}
public WinNT.HRESULT BindToObject(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[5], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
}
@Override
public HRESULT BindToStorage(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[6], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
}
@Override
public HRESULT CompareIDs(WinDef.LPARAM lParam, Pointer pidl1, Pointer pidl2) {
Function f = Function.getFunction(vTable[7], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, lParam, pidl1, pidl2 }));
}
@Override
public HRESULT CreateViewObject(WinDef.HWND hwndOwner, REFIID riid, PointerByReference ppv) {
Function f = Function.getFunction(vTable[8], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwndOwner, riid, ppv }));
}
@Override
public HRESULT GetAttributesOf(int cidl, Pointer apidl, IntByReference rgfInOut) {
Function f = Function.getFunction(vTable[9], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, cidl, apidl, rgfInOut }));
}
@Override
public HRESULT GetUIObjectOf(WinDef.HWND hwndOwner, int cidl, Pointer apidl, REFIID riid,
IntByReference rgfReserved, PointerByReference ppv) {
Function f = Function.getFunction(vTable[10], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(
new Object[] { interfacePointer, hwndOwner, cidl, apidl, riid, rgfReserved, ppv }));
}
public WinNT.HRESULT GetDisplayNameOf(Pointer pidl, int flags, STRRET pName) {
Function f = Function.getFunction(vTable[11], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, flags, pName }));
}
@Override
public HRESULT SetNameOf(WinDef.HWND hwnd, Pointer pidl, String pszName, int uFlags,
PointerByReference ppidlOut) {
Function f = Function.getFunction(vTable[12], Function.ALT_CONVENTION);
return new WinNT.HRESULT(
f.invokeInt(new Object[] { interfacePointer, hwnd, pidl, pszName, uFlags, ppidlOut }));
}
// OLD VERSION THAT YOU WANT TO IGNORE BUT MUST DECLARE
@Override
public HRESULT ParseDisplayName(HWND hwnd, Pointer pbc, String pszDisplayName, IntByReference pchEaten,
PointerByReference ppidl, IntByReference pdwAttributes) {
return null;
}
};
}
}
}