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

问题描述 投票:0回答:1

我正在使用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函数调用的一部分,我错过了什么来正确传递负整数?

c++ mfc com atl variant
1个回答
2
投票

问题是你在滥用VARIANT

你将vaCountvt字段设置为VT_INT 1,但然后将你的int值分配给它的.iVal字段而不是.intVal字段。 .iVal场是用于short的16比特VT_I2,而.intVal是用于int的32比特VT_INT

同样地,你将vaUnitvt设置为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;
}
© www.soinside.com 2019 - 2024. All rights reserved.