英文:
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) { ... }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论