Как создать SAFEARRAY указателей на ВАРИАНТЫ?

Меньше служебное (никакой конверт SOAP для обертывания каждого призывать)

Меньшему количеству дублирования (HTTP уже представляет операции, нравится, УДАЛЯЮТ, ПОМЕЩАЮТ, ДОБИРАЮТСЯ, и т.д. которые должны иначе быть представлены в конверте SOAP).

Более стандартизированный - операции HTTP хорошо поняты и последовательно работают. Некоторые реализации SOAP могут стать привередливыми.

более человекочитаемый и тестируемый (тяжелее для тестирования SOAP только с браузером).

не должны использовать XML (хорошо, Вы отчасти не имеете к для SOAP ни один, но это едва имеет смысл, так как Вы уже делаете парсинг конверта).

Библиотеки сделали SOAP (довольно) легким. Но Вы абстрагируете далеко большое дублирование внизу, как я отметил. да в теории SOAP может пробежаться через другие транспорты, чтобы не ехать на слое, делающем подобные вещи, но в действительности примерно вся работа SOAP, которую Вы будете когда-либо делать, по HTTP.

6
задан Shog9 9 July 2010 в 19:58
поделиться

1 ответ

Определение SAFEARRAY (VARIANT *) не совсем корректно. Он объявлен в IDL как SAFEARRAY (VARIANT), но указатель, доступный после блокировки SAFEARRAY, на самом деле является VARIANT *. Если вы задумаетесь об этом на мгновение, это должно иметь больше смысла. Указатель индекса SAFEARRAY (член pvData) не может вместить весь VARIANT в его физическом расположении, поэтому, по крайней мере, он должен иметь возможность хранить указатель, который может использоваться для индексации в массив VARIANT.

Если вы посмотрите на , где-то около строки 1110+ вы увидите определения перечисления VT_. Там также показано, что VT_VARIANT на самом деле подразумевает VARIANT *. Также удобны теги [S] , указывающие, какие элементы могут появиться в SAFEARRAY.

/*
 * VARENUM usage key,
 *
 * * [V] - may appear in a VARIANT
 * * [T] - may appear in a TYPEDESC
 * * [P] - may appear in an OLE property set
 * * [S] - may appear in a Safe Array
 *
 *
 *  VT_EMPTY            [V]   [P]     nothing
 *  VT_NULL             [V]   [P]     SQL style Null
 *  VT_I2               [V][T][P][S]  2 byte signed int
 *  VT_I4               [V][T][P][S]  4 byte signed int
 *  VT_R4               [V][T][P][S]  4 byte real
 *  VT_R8               [V][T][P][S]  8 byte real
 *  VT_CY               [V][T][P][S]  currency
 *  VT_DATE             [V][T][P][S]  date
 *  VT_BSTR             [V][T][P][S]  OLE Automation string
 *  VT_DISPATCH         [V][T]   [S]  IDispatch *
 *  VT_ERROR            [V][T][P][S]  SCODE
 *  VT_BOOL             [V][T][P][S]  True=-1, False=0
 *  VT_VARIANT          [V][T][P][S]  VARIANT *
 ... (remaining definitions omittted)
 */

Вот ссылка на копию файла заголовка.

wtypes.h в DOC. DDART.NET

Исходя из этого, вы должны просто объявить SAFEARRAY с вариантным типом VT_VARIANT, а затем рассматривать pvData как VARIANT * при блокировке массива. Вот исходный код для примера консольного приложения win32, который демонстрирует это, вызывая функцию, соответствующую тому же объявлению, что и ваша функция.

#include "stdafx.h"
#include "SFAComponent.h"
#include "SFAComponent_i.c"

int _tmain(int argc, _TCHAR* argv[])
{
  ::CoInitialize(NULL);

  SAFEARRAYBOUND nameBounds;
  nameBounds.cElements = 2;
  nameBounds.lLbound = 0;
  LPSAFEARRAY psaNames = SafeArrayCreate(VT_BSTR, 1, &nameBounds);

  BSTR bstrApple = SysAllocString(L"apple");
  BSTR bstrOrange = SysAllocString(L"orange");

  SafeArrayLock(psaNames);
  BSTR *nameArray = (BSTR *)psaNames->pvData;
  nameArray[0] = bstrApple;
  nameArray[1] = bstrOrange;
  SafeArrayUnlock(psaNames);

  SAFEARRAYBOUND valueBounds;
  valueBounds.cElements = 2;
  valueBounds.lLbound = 0;
  LPSAFEARRAY psaValues = SafeArrayCreate(VT_VARIANT, 1, &valueBounds);

  SafeArrayLock(psaValues);
  VARIANT *valueArray = (VARIANT *)psaValues->pvData;
  VariantClear(&valueArray[0]);
  VariantClear(&valueArray[1]);
  valueArray[0].vt = VT_BSTR;
  valueArray[0].bstrVal = SysAllocString(L"hello");
  valueArray[1].vt = VT_I4;
  valueArray[1].iVal = 42;

  {
    CComPtr<ITestReader> p;
    p.CoCreateInstance(CLSID_TestReader);
    p->Run(psaNames, psaValues);
    p.Release(); // not explicitly necessary.
  }

  SafeArrayDestroy(psaValues);
  SafeArrayDestroy(psaNames);

  ::CoUninitialize();

  return 0;
}

Компонент, вызываемый этим тестовым приложением, может быть создан путем создания проекта DLL ATL и добавления простого Объект ATL с именем TestReader.

Вот IDL для ITestReader.

[
  object,
  uuid(832EF93A-18E8-4655-84CA-0BA847B52B77),
  dual,
  nonextensible,
  helpstring("ITestReader Interface"),
  pointer_default(unique),
  oleautomation
]
interface ITestReader : IDispatch{
  [id(1), helpstring("method Run")] HRESULT Run([in] SAFEARRAY(BSTR) paramNames, [in] SAFEARRAY(VARIANT) paramValues);
};

Функция-член, соответствующая объявлению IDL, просто принимает аргументы SAFEARRAY * (или LPSAFEARRAY).

public:
  STDMETHOD(Run)(LPSAFEARRAY paramNames, LPSAFEARRAY paramValues);

Вот тело метода. Также для краткости включена вспомогательная функция PrintVariant ().

void PrintVariant(VARIANT *pV)
{
  switch(pV->vt)
  {
  case VT_BSTR:
    wprintf(L"  BSTR: %s\r\n", pV->bstrVal);
    break;
  case VT_I4:
    wprintf(L"  Integer: %d\r\n", pV->iVal);
    break;
  default:
    wprintf(L"  Unrecognized Type: vt=%d\r\n", pV->vt);
    break;
  }
}

STDMETHODIMP CTestReader::Run(LPSAFEARRAY paramNames, LPSAFEARRAY paramValues)
{
  SafeArrayLock(paramNames);
  SafeArrayLock(paramValues);
  BSTR *nameArray = (BSTR *)paramNames->pvData;
  VARIANT *valueArray = (VARIANT *)paramValues->pvData;

  wprintf(L"Item 0 is %s, variant type %d\r\n", nameArray[0], valueArray[0].vt);
  PrintVariant(&valueArray[0]);
  wprintf(L"Item 1 is %s, variant type %d\r\n", nameArray[1], valueArray[1].vt);
  PrintVariant(&valueArray[1]);

  SafeArrayUnlock(paramNames);
  SafeArrayUnlock(paramValues);

  return S_OK;
}
6
ответ дан 8 December 2019 в 17:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: