我正在使用Visual Studio 2010中基于C ++ / ATL的Microsoft Word加载项。我还使用基于MFC的COleDispatchDriver
和支持类,并使用Visual Studio的ClassWizard从Microsoft Word类型库生成包装类。下面是ClassWizard生成的Selection.Move函数的示例包装器。
long Move(VARIANT * Unit, VARIANT * Count)
{
long result;
static BYTE parms[] = VTS_PVARIANT VTS_PVARIANT ;
InvokeHelper(0x6d, DISPATCH_METHOD, VT_I4, (void*)&result, parms, Unit, Count);
return result;
}
对于上面的函数,我还编写了辅助函数来处理VARIANT参数传递,如下所示。
long Move(int Unit, int Count)
{
long result;
static BYTE parms[] = VTS_PVARIANT VTS_PVARIANT ;
VARIANT vaUnit;
::VariantInit(&vaUnit);
vaUnit.vt = VT_I4;
vaUnit.iVal = Unit;
VARIANT vaCount;
::VariantInit(&vaCount);
vaCount.vt = VT_INT;
vaCount.iVal = Count;
InvokeHelper(0x6d, DISPATCH_METHOD, VT_I4, (void*)&result, parms, &vaUnit, &vaCount);
::VariantClear(&vaUnit);
::VariantClear(&vaCount);
return result;
}
当我使用Count
参数的正整数调用我的函数时,Word会正确响应,例如以下函数调用将选择“向前”(朝向文档末尾)移动一个字符。
m_oSelection.Move(1 /* wdCharacter */, 1);
但是,如果我尝试使用以下函数调用将一个字符“向后”(朝向文档的开头)移动,则Word不会按预期响应。
m_oSelection.Move(1 /* wdCharacter */, -1);
看起来像“Word自动化”将整数视为无符号整数,而我的-1值变为65535,导致选择向前跳转。使用vaCount
函数调用检查行上的InvokeHelper
变量,VS调试器将.iVal
值显示为-1,但vaCount
变量的“值”显示为65535。
作为COM函数调用的一部分,我错过了什么来正确传递负整数?
VARIANT
。你将vaCount
的vt
字段设置为VT_INT
1,但然后将你的int
值分配给它的.iVal
字段而不是.intVal
字段。 .iVal
场是用于short
的16比特VT_I2
,而.intVal
是用于int
的32比特VT_INT
。
同样地,你将vaUnit
的vt
设置为VT_I4
但是然后将int
值分配给它的.iVal
字段,而不是它的.lVal
字段,这是一个32位long
。
1:你为什么要使用VT_INT
而不是更传统的VT_I4
?
试试这个:
long Move(int Unit, int Count)
{
long result;
static BYTE parms[] = VTS_PVARIANT VTS_PVARIANT ;
VARIANT vaUnit;
::VariantInit(&vaUnit);
vaUnit.vt = VT_I4;
vaUnit.lVal = Unit;
VARIANT vaCount;
::VariantInit(&vaCount);
vaCount.vt = VT_I4;
vaCount.lVal = Count;
InvokeHelper(0x6d, DISPATCH_METHOD, VT_I4, (void*)&result, parms, &vaUnit, &vaCount);
::VariantClear(&vaUnit);
::VariantClear(&vaCount);
return result;
}
话虽这么说,我建议你使用CComVariant
或_variant_t
包装类,而不是直接使用VARIANT
,让它为你处理这些细节。另外,因为InvokeHelper()
在失败时抛出异常,所以让包装器在超出范围时为你调用VariantClear()
:
long Move(int Unit, int Count)
{
long result;
static BYTE parms[] = VTS_PVARIANT VTS_PVARIANT ;
CComVariant vaUnit(Unit);
CComVariant vaCount(Count);
InvokeHelper(0x6d, DISPATCH_METHOD, VT_I4, (void*)&result, parms, &vaUnit, &vaCount);
return result;
}
long Move(int Unit, int Count)
{
long result;
static BYTE parms[] = VTS_PVARIANT VTS_PVARIANT ;
_variant_t vaUnit(Unit);
_variant_t vaCount(Count);
InvokeHelper(0x6d, DISPATCH_METHOD, VT_I4, (void*)&result, parms, &vaUnit, &vaCount);
return result;
}