Отправка и получение массивов через COM - PullRequest
3 голосов
/ 10 февраля 2012

Как правильно получать и отправлять массивы через COM? Вот моя попытка: надежный массив пар, завернутый в вариант.

//takes variant holding safearray of doubles
//returns a similar variant having multipled every element by 2
STDMETHODIMP MyComClass::safearraytimestwo(VARIANT in, VARIANT* out)
{
    CComSafeArray<double> sa_in;
    sa_in.Attach(*in.pparray);
    ULONG size = sa_in.GetCount();

    CComSafeArray<double> *out_sa = new CComSafeArray<double>(size);

    for (long i=0;i<size;i++)
        out_sa->SetAt(i,sa_in[i]*2);

    out = new CComVariant(out_sa);
    return S_OK;
}

Проблемы: - в настоящее время компиляция не выполняется в цикле: error C2679: binary '=' : no operator found which takes a right-hand operand of type 'ATL::_ATL_AutomationType<DOUBLE>::_typewrapper' (or there is no acceptable conversion) edit: решено с использованием SetAt() вместо operator[] - Должен ли я объявить out_sa в куче? Будет ли он освобожден, когда out будет освобожден (что я могу только предположить, что клиент сделает?)

Любая помощь будет принята с благодарностью!

Редактировать 2: это частичная реализация, которая пытается просто вернуть страховочный массив.

STDMETHODIMP CSpatialNet::array3(VARIANT in, VARIANT* out)
{
    CComSafeArray<double> out_sa;
    out_sa.Create(2);
    out_sa.SetAt(0,1.2);
    out_sa.SetAt(1,3.4);
    *out = CComVariant(out_sa);
    out_sa.Detach();
    return S_OK;
}

Это также не помогает; отчеты lisp

(vl-load-com)
(setq n (vlax-create-object "sdnacomwrapper.SpatialNet"))
(setq v (vlax-make-variant 1.0))
(vlax-invoke-method n 'array3 v 'newvar)
; error: ActiveX Server returned an error: The parameter is incorrect

Замена CComSafeArray<double> массивом вариантов приводит к той же ошибке.

Ответы [ 2 ]

5 голосов
/ 14 февраля 2012

Понял, что работает - правильный код такой:

STDMETHODIMP MyComClass::arraytimestwo(VARIANT in, VARIANT* out)
{
    CComSafeArray<double> sa_in;
    sa_in.Attach(in.parray);
    ULONG size = sa_in.GetCount();
    CComSafeArray<double> out_sa;
    out_sa.Create(size);
    for (long i=0;i<size;i++)
        out_sa.SetAt(i,sa_in.GetAt(i)*2);

    CComVariant(out_sa).Detach(out);
    return S_OK;
}

А в Лиспе ...

(vl-load-com)
(setq n (vlax-create-object "mycomdll.MyComClass"))
(setq sa (vlax-make-safearray vlax-vbDouble '(0 . 1)))
(vlax-safearray-fill sa '(1 2))
(vlax-safearray->list sa)
(vlax-invoke-method n 'arraytimestwo sa 'newvar)
(vlax-safearray->list newvar)

Что не так с исходными попытками:

  • необходимо использовать метод Detach для присвоения значения out
  • , необходимого для присоединения к in.parray, а не *in.pparray (не то же самое)
1 голос
/ 27 декабря 2013

Метод COM, принимающий параметры VARIANT, отвечает за проверку аргументов, за перехват исключений и не собирается фактически уничтожать массив [in], поэтому более точная реализация на стороне C ++ будет:

STDMETHODIMP Foo(VARIANT in, VARIANT* out)
{
    _ATLTRY
    {
        ATLENSURE_THROW(in.vt == (VT_ARRAY | VT_R8), E_INVALIDARG);
        ATLENSURE_THROW(out, E_POINTER);
        VariantInit(out);
        CComSafeArray<DOUBLE>& sa_in =
            reinterpret_cast<CComSafeArray<DOUBLE>&>(in.parray);
        ULONG size = sa_in.GetCount();
        CComSafeArray<DOUBLE> out_sa;
        ATLENSURE_SUCCEEDED(out_sa.Create(size));
        for(ULONG nIndex = 0; nIndex < size; nIndex++)
            out_sa.SetAt(nIndex, sa_in.GetAt(nIndex) * 2);
        // NOTE: Constructor copies data so it's accurate just inefficient
        ATLVERIFY(SUCCEEDED(CComVariant(out_sa).Detach(out)));
    }
    _ATLCATCH(Exception)
    {
        return Exception;
    }
    return S_OK;
}
...