如何将负整数传递给COM/OLE函数

How to Pass Negative Integer to COM/OLE Function?

本文关键字:COM OLE 函数 整数      更新时间:2023-10-16

我正在基于Visual Studio 2010中基于C /ATL的Microsoft Word加载项。我还使用基于MFC的COleDispatchDriver并支持类,并使用Visual Studio的ClassWizard生成了ClassWizardMicrosoft Word类型库中的包装类类。classwizard生成的选择函数的样本包装器在下面。

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

对于上述功能,我还编写了助手功能来照顾通过的变体参数,如下所示。

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

它看起来"似乎"一词将整数视为无符号整数,而我的-1值变为65535,导致选择向前跳。使用InvokeHelper函数调用在线上检查vaCount变体,VS调试器将.iVal值显示为-1,但vaCount变体的"值"显示为65535。

作为com函数呼叫的一部分,我缺少适当地传递负整数?

问题是您正在滥用VARIANT

您将vaCountvt字段设置为VT_INT 1 ,但是然后将int值分配给其.iVal字段而不是其.intVal字段。.iVal字段是用于VT_I2的16位short,而.intValVT_INT使用的32bit int

同样,您将vaUnitvt设置为VT_I4,但随后也将int值分配给其.iVal字段,而不是其.lVal字段,即32bit 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;
}