如何将负整数传递给 COM/OLE 函数?
How to Pass Negative Integer to COM/OLE Function?
我正在 Visual Studio 2010 年开发基于 C++/ATL 的 Microsoft Word 加载项。我也在使用基于 MFC 的 COleDispatchDriver
并支持 类 并使用Visual Studio 的类向导从 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 会正确响应,例如以下函数调用会将选择 "forward"(向文档末尾)移动一个字符。
m_oSelection.Move(1 /* wdCharacter */, 1);
但是,如果我尝试使用以下函数调用将所选内容移动一个字符 "backward"(朝向文档的开头),Word 不会按预期响应。
m_oSelection.Move(1 /* wdCharacter */, -1);
它 "seems" 就像 Word 自动化将整数视为无符号整数,我的 -1 值变为 65535 导致选择向前跳转。通过 InvokeHelper
函数调用检查行上的 vaCount
变体,VS 调试器将 .iVal
值显示为 -1,但 vaCount
的 "value"变体显示为 65535。
为了在 COM 函数调用中适当地传递负整数,我错过了什么?
问题是您误用了 VARIANT
。
您正在将 vaCount
的 vt
字段设置为 VT_INT
1,但随后将您的 int
值分配给它的 .iVal
字段而不是 .intVal
字段。 .iVal
字段是用于 VT_I2
的 16 位 short
,而 .intVal
是用于 VT_INT
.[=41 的 32 位 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
or _variant_t
包装器 class 而不是直接使用 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;
}
我正在 Visual Studio 2010 年开发基于 C++/ATL 的 Microsoft Word 加载项。我也在使用基于 MFC 的 COleDispatchDriver
并支持 类 并使用Visual Studio 的类向导从 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 会正确响应,例如以下函数调用会将选择 "forward"(向文档末尾)移动一个字符。
m_oSelection.Move(1 /* wdCharacter */, 1);
但是,如果我尝试使用以下函数调用将所选内容移动一个字符 "backward"(朝向文档的开头),Word 不会按预期响应。
m_oSelection.Move(1 /* wdCharacter */, -1);
它 "seems" 就像 Word 自动化将整数视为无符号整数,我的 -1 值变为 65535 导致选择向前跳转。通过 InvokeHelper
函数调用检查行上的 vaCount
变体,VS 调试器将 .iVal
值显示为 -1,但 vaCount
的 "value"变体显示为 65535。
为了在 COM 函数调用中适当地传递负整数,我错过了什么?
问题是您误用了 VARIANT
。
您正在将 vaCount
的 vt
字段设置为 VT_INT
1,但随后将您的 int
值分配给它的 .iVal
字段而不是 .intVal
字段。 .iVal
字段是用于 VT_I2
的 16 位 short
,而 .intVal
是用于 VT_INT
.[=41 的 32 位 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
or _variant_t
包装器 class 而不是直接使用 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;
}