Sending and receiving arrays over COM

霸气de小男生 提交于 2019-12-05 23:22:07

Got this working - the correct code is this:

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

And in Lisp...

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

Things specifically wrong with the original attempts:

  • needed to use Detach method to assign value to out
  • needed to attach to in.parray not *in.pparray (not the same thing)

A COM method taking VARIANT parameters is responsible for checking arguments, for catching exceptions and it is not going to actually destroy [in] array, so a more accurate implementation on C++ side would be:

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!