调试JNA中的COM接口映射

huangapple go评论77阅读模式
英文:

Debugging COM interface mapping in JNA

问题

在将 Vss.h 和其他几个头文件映射到Java/JNA后(参见此问题),我试图运行一些COM对象方法,并且在调试它们时遇到了问题。

我不知道我是否正在调用正确的方法,还是调用了参数类似的方法。在JNA文档中,我在这里找到了一些错误代码链接,但它并未包含我所看到的所有错误。

以下是一些例子:

// 收集写入器元数据
public int GatherWriterMetadata(IVssAsync pAsync)
{
    return _invokeNativeInt(5, new Object[] { getPointer(), pAsync });
}

我遇到了错误码 -2147212542

对于以下代码:

// 用于设置随后的快照相关操作的上下文
public int SetContext(WinDef.LONG lContext)
{
    return _invokeNativeInt(32, new Object[] { getPointer(), lContext });
}

我遇到了以下错误:

java.lang.Error: 无效的内存访问
	at com.sun.jna.Native.invokeInt(Native Method)

我尝试过为 SetContext 方法使用数字 31、32 和 33。

英文:

After mapping Vss.h and several others headers to Java/JNA (see this question) I am trying to run some of the COM object methods and have a problem debugging them.

I do not know if I am calling the correct method or one with similar parameters. Some of the error codes I find in the JNA documentation here, but it does not include all the errors I am seeing.

Some examples:

// gather writer metadata
public int GatherWriterMetadata(IVssAsync pAsync)
{
    return _invokeNativeInt( 5, new Object[] { getPointer(), pAsync });
}

I have error -2147212542

For

// Called to set the context for subsequent snapshot-related operations
public int SetContext(WinDef.LONG lContext)
{
    return _invokeNativeInt( 32, new Object[] { getPointer(), lContext });
}

I have
java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)

I've tried to play with a numbers like 31,32 and 33 for the SetContext method.

答案1

得分: 0

不要尝试去"玩弄数字",因为你可能会遇到随机行为。

正如我在对你另一个问题的回答中所提到的,整数vtblId值用于_invokeNative...调用,必须来自头文件中的Vtbl结构。我没有直接访问头文件的权限,但是Rust中的这个映射可能适合使用,但由于这个接口(以及所有的COM接口)都继承自IUnknown,它已经包括了QueryInterface()AddRef()Release()函数,它们分别占据了vtblId的值为0、1和2

你的GatherWriterMetadata方法,使用vtblId为5,实际上是在调用InitializeForBackup()函数,该函数需要一个BSTR参数。你给它了一些其他的参数,所以它返回了一个错误。(如果按十进制值-2147212542查找错误不起作用,你可以将其转换为补码十六进制,即0x80042302,一个系统还原错误。)

根据我的计算,你应该在GatherWriterMetadata中使用vtblId为9。请自行计算以确认。

根据我的计算,你的SetContext方法应该使用vtblId为35。同样,请计算函数的数量(从3开始),以自行确认这一点。

另外,我注意到你在大多数这些函数的返回类型中使用了int类型,而不是HRESULT。由于HRESULT最终是一个32位整数类型,这样做是可以的。然而,如果你实际上使用HRESULT作为返回值,你就可以使用更方便/自我说明的错误处理方法,比如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) { ... }
英文:

Do not try to "play with numbers" as you are likely to experience random behavior.

As I mentioned in my answer to your other question 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.

Your GatherWriterMetadata method, using a vtblId of 5, is actually invoking the InitializeForBackup() function, which expects a BSTR argument. You are giving it some other argument, so it is returning an error. (If looking up an error by the decimal value -2147212542 doesn't work, you can translate to two's-complement hex, which in this case is 0x80042302, a System Restore Error.)

By my count, you should be using vtblId of 9 for GatherWriterMetadata. Please count for yourself to confirm.

Your SetContext method, by my count should be using vtblId of 35. Again, please count the number of functions (starting at 3) to confirm this for yourself.

Also, I see you've used an int type for the return type for most of these functions rather than HRESULT. Since HRESULT is eventually a 32-bit integer type, this will work. However, if you actually use HRESULT as the return value you gain access to more convenient/self-documenting error-handling methods like COMUtils.SUCCEEDED() and COMUtils.FAILED(), or even the COMUtils.checkRC() method which throws a nicely formatted COMException on failure.

So your mappings should probably be:

// gather writer metadata
public HRESULT GatherWriterMetadata(IVssAsync pAsync)
{
    return _invokeNativeObject( 9,
        new Object[] { getPointer(), pAsync }, HRESULT.class);
}

and

// 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);
}

Incidentally, since the Windows LONG type is always 32-bits, you could also simplify the second mapping to:

public HRESULT SetContext(int lContext) { ... }

huangapple
  • 本文由 发表于 2020年7月27日 01:51:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63103697.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定