在 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) { ... }