Как передать отрицательное целое число в функцию COM / OLE? - PullRequest
0 голосов
/ 14 февраля 2019

Я работаю над надстройкой Microsoft Word на основе C ++ / ATL в Visual Studio 2010. Я также использую COleDispatchDriver на основе MFC и поддерживаю классы и использую ClassWizard Visual Studio для генерации классов-оболочек из Microsoft Wordбиблиотека типов.Пример оболочки для функции Selection.Move, сгенерированной 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;
}

Для функций, подобных приведенной выше, я также написал вспомогательные функции, обеспечивающие передачу аргумента 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?

1 Ответ

0 голосов
/ 14 февраля 2019

Проблема в том, что вы неправильно используете VARIANT.

Вы устанавливаете поле vt vaCount на VT_INT 1 , но затем присваиваете свой int значение в поле .iVal вместо поля .intVal.Поле .iVal - это 16-битное short, которое используется для VT_I2, тогда как .intVal - это 32-битное int, используемое с VT_INT.

Аналогично, вы устанавливаете vaUnit 's 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;
}
...