在 JNA 中调试 COM 接口映射
Debugging COM interface mapping in JNA
在将 Vss.h
和其他几个 headers 映射到 Java/JNA () 之后,我正在尝试 运行 某些 COM object 方法并在调试它们时遇到问题。
我不知道我是在调用正确的方法还是具有相似参数的方法。我在 JNA 文档 here 中找到的一些错误代码,但它不包括我看到的所有错误。
一些示例:
// gather writer metadata
public int GatherWriterMetadata(IVssAsync pAsync)
{
return _invokeNativeInt( 5, new Object[] { getPointer(), pAsync });
}
我有错误-2147212542
对于
// Called to set the context for subsequent snapshot-related operations
public int SetContext(WinDef.LONG lContext)
{
return _invokeNativeInt( 32, new Object[] { getPointer(), lContext });
}
我有
java.lang.Error: 无效内存访问
在 com.sun.jna.Native.invokeInt(本机方法)
我尝试在 SetContext 方法中使用 31,32 和 33 等数字。
不要尝试“玩数字”,因为您可能会遇到随机行为。
正如我在 the integer vtblId
value for the _invokeNative...
calls has to come from the Vtbl
structure in the header file. I don't have direct access to the header file, but this mapping from Rust is probably good to use, but since this interface (and all COM interfaces) extends IUnknown
, it already includes the functions QueryInterface()
, AddRef()
, and Release()
, which take up vtblId
values 0, 1, and 2 中提到的那样。
您的 GatherWriterMetadata
方法使用的 vtblId
为 5,实际上是在调用 InitializeForBackup()
函数,该函数需要一个 BSTR
参数。你给了它一些其他的参数,所以它 returning 是一个错误。 (如果通过十进制值 -2147212542 查找错误不起作用,您可以转换为二进制补码十六进制,在本例中为 0x80042302
,系统还原错误。)
根据我的计算,您应该使用 vtblId
,共 9 个用于 GatherWriterMetadata
。请自己数数确认。
你的SetContext
方法,根据我的计算应该使用vtblId
,共35个。再次,请计算函数的数量(从3开始)以自己确认。
此外,我看到您为这些函数中的大多数 return 类型使用了 int 类型,而不是 HRESULT
。由于 HRESULT
最终是一个 32 位整数类型,因此这将起作用。但是,如果您实际使用 HRESULT
作为 return 值,您可以访问更多 convenient/self-documenting 错误处理方法,例如 COMUtils.SUCCEEDED()
和 COMUtils.FAILED()
,甚至 COMUtils.checkRC()
方法在失败时抛出格式良好的 COMException
。
所以你的映射应该是:
// gather writer metadata
public HRESULT GatherWriterMetadata(IVssAsync pAsync)
{
return _invokeNativeObject( 9,
new Object[] { getPointer(), pAsync }, HRESULT.class);
}
和
// Called to set the context for subsequent snapshot-related operations
public HRESULT SetContext(WinDef.LONG lContext)
{
return _invokeNativeObject( 35,
new Object[] { getPointer(), lContext }, HRESULT.class);
}
顺便说一句,由于 Windows LONG
类型始终是 32 位,您还可以将第二个映射简化为:
public HRESULT SetContext(int lContext) { ... }
在将 Vss.h
和其他几个 headers 映射到 Java/JNA (
我不知道我是在调用正确的方法还是具有相似参数的方法。我在 JNA 文档 here 中找到的一些错误代码,但它不包括我看到的所有错误。
一些示例:
// gather writer metadata
public int GatherWriterMetadata(IVssAsync pAsync)
{
return _invokeNativeInt( 5, new Object[] { getPointer(), pAsync });
}
我有错误-2147212542
对于
// Called to set the context for subsequent snapshot-related operations
public int SetContext(WinDef.LONG lContext)
{
return _invokeNativeInt( 32, new Object[] { getPointer(), lContext });
}
我有 java.lang.Error: 无效内存访问 在 com.sun.jna.Native.invokeInt(本机方法)
我尝试在 SetContext 方法中使用 31,32 和 33 等数字。
不要尝试“玩数字”,因为您可能会遇到随机行为。
正如我在 vtblId
value for the _invokeNative...
calls has to come from the Vtbl
structure in the header file. I don't have direct access to the header file, but this mapping from Rust is probably good to use, but since this interface (and all COM interfaces) extends IUnknown
, it already includes the functions QueryInterface()
, AddRef()
, and Release()
, which take up vtblId
values 0, 1, and 2 中提到的那样。
您的 GatherWriterMetadata
方法使用的 vtblId
为 5,实际上是在调用 InitializeForBackup()
函数,该函数需要一个 BSTR
参数。你给了它一些其他的参数,所以它 returning 是一个错误。 (如果通过十进制值 -2147212542 查找错误不起作用,您可以转换为二进制补码十六进制,在本例中为 0x80042302
,系统还原错误。)
根据我的计算,您应该使用 vtblId
,共 9 个用于 GatherWriterMetadata
。请自己数数确认。
你的SetContext
方法,根据我的计算应该使用vtblId
,共35个。再次,请计算函数的数量(从3开始)以自己确认。
此外,我看到您为这些函数中的大多数 return 类型使用了 int 类型,而不是 HRESULT
。由于 HRESULT
最终是一个 32 位整数类型,因此这将起作用。但是,如果您实际使用 HRESULT
作为 return 值,您可以访问更多 convenient/self-documenting 错误处理方法,例如 COMUtils.SUCCEEDED()
和 COMUtils.FAILED()
,甚至 COMUtils.checkRC()
方法在失败时抛出格式良好的 COMException
。
所以你的映射应该是:
// gather writer metadata
public HRESULT GatherWriterMetadata(IVssAsync pAsync)
{
return _invokeNativeObject( 9,
new Object[] { getPointer(), pAsync }, HRESULT.class);
}
和
// Called to set the context for subsequent snapshot-related operations
public HRESULT SetContext(WinDef.LONG lContext)
{
return _invokeNativeObject( 35,
new Object[] { getPointer(), lContext }, HRESULT.class);
}
顺便说一句,由于 Windows LONG
类型始终是 32 位,您还可以将第二个映射简化为:
public HRESULT SetContext(int lContext) { ... }