通过COM发送和接收阵列 [英] Sending and receiving arrays over COM

查看:109
本文介绍了通过COM发送和接收阵列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过COM接收和发送数组的正确方法是什么?到目前为止,这是我的尝试:将一个安全的双精度数组包装在一个变量中.

What is the right way to receive and send arrays over COM? Here's my attempt so far: a safearray of doubles wrapped in a variant.

//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) 使用SetAt()而不是operator[] 解决 -我应该在堆上声明out_sa吗?当out被释放时,它是否会被释放(我只能假定客户端会这样做?)

Problems: - currently compilation fails on the loop operation: 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: solved using SetAt() instead of operator[] - Should I be declaring out_sa on the heap? Will it get deallocated when out gets deallocated (which I can only presume the client will do?)

任何帮助将不胜感激!

这是部分实现,试图仅返回安全数组.

Edit 2: here is a partial implementation that tries just to return a safearray.

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报告

This also fails; lisp reports

(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>会产生相同的错误.

Replacing CComSafeArray<double> with an array of variants produces the same error.

推荐答案

Sideshow Bob和Roman R.的解决方案使用

The solutions of Sideshow Bob and Roman R. use

ComVariant(out_sa).Detach(out);

这有一个严重的缺点. SAFEARRAY out_sa被传递给CComVariant's构造函数,构造函数将复制SAFEARRAY.为了避免更好地使用副本

This has a serious drawback. The SAFEARRAY out_sa is passed to the CComVariant's constructor and the constructor will make a copy of the SAFEARRAY. To avoid a copy better use

::VariantInit(out);
out->vt = (VT_ARRAY | VT_R8);
out->parray = out_sa.Detach();

正如罗曼指出的那样,您还应该首先检查in是否确实是VT_ARRAY | VT_R8类型.鲍勃的解决方案存在严重缺陷:in.parray已附加到sa_in,但未分离,因此析构函数将销毁in.parray.但是根据COM的规则,不允许功能arraytimestwo(VARIANT in,...修改自变量in. COM充满陷阱.因此,我认为最好通过引用传递参数in.

As Roman pointed out, you should also start with checking whether in really is of type VT_ARRAY | VT_R8. Bob's solution has imho a serious fault: in.parray is attached to sa_in but not detached and thus the destructor will destroy in.parray. But by the rules of COM, the function arraytimestwo(VARIANT in,...is not allowed to modify the argument in. COM is full of traps. Therefore, I think it's better to pass the parameter in by reference.

我(希望!)提供了一个改进的解决方案和一个测试功能:

I give a (hopefully!) improved solution and a test function:

STDMETHODIMP arraytimestwo(const VARIANT &in, VARIANT* out)
{
  try
  {
    if (in.vt != (VT_ARRAY | VT_R8)) return E_INVALIDARG;
    CComSafeArray<double> sa_out;
    variant_t wrapCopyIn(in);
    sa_out.Attach(wrapCopyIn.parray);
    if (sa_out.GetDimensions() > 1) return E_INVALIDARG;

    for (long i = sa_out.GetLowerBound(0); i <= sa_out.GetUpperBound(0); i++)
       sa_out[i] *= 2;
    //Don't forget
    sa_out.Detach();

    *out = wrapCopyIn.Detach();
  }
  catch (const CAtlException& e)
  {
    // Exception object implicitly converted to HRESULT,
    // and returned as an error code to the caller
    return e;
  }
  return S_OK;
}

void TestArraytimestwo()
{
  CComSafeArray<double> vec(5, 1);
  for (int i = vec.GetLowerBound(); i <= vec.GetUpperBound(); i++) vec[i] = i * 1.1;

  variant_t in, out;
  in.vt = (VT_ARRAY | VT_R8);
  in.parray = vec.Detach();

  if (!SUCCEEDED(arraytimestwo(in, &out)))
  {
   std::cout << "Something went wrong!" << "\n";
   return;
  }

  CComSafeArray<double> sa_out;
  sa_out.Attach(out.parray);
  vec.Attach(in.parray);
  for (int i = vec.GetLowerBound(); i <= vec.GetUpperBound(); i++)
     std::cout << vec[i] << "  " << sa_out[i] << std::endl;

  //Not necessary, but I do it out of habit
  vec.Detach();
  sa_out.Detach();
}

备注:Bob的原始功能应如下所示(跳过try ... catch)

Remark: Bob's original function should be like this (skipping try ... catch)

STDMETHODIMP arraytimestwoBob(const VARIANT &in, VARIANT* out)
{
  CComSafeArray<double> sa_in;
  sa_in.Attach(in.parray);
  CComSafeArray<double> out_sa(sa_in.GetCount(), sa_in.GetLowerBound());
  for (long i = sa_in.GetLowerBound(); i <= sa_in.GetUpperBound(); i++) out_sa[i] = 2 * sa_in[i];
  sa_in.Detach();//Detach, this function doesn't own in 
  ::VariantInit(out);
  out->vt = (VT_ARRAY | VT_R8);
  out->parray = out_sa.Detach();
  return S_OK;
}

这篇关于通过COM发送和接收阵列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆