通过COM发送和接收阵列
Sending and receiving arrays over COM
通过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)
编辑:使用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>
会产生相同的错误。
实现了这一点-我的代码是这样的(编辑:尽管显然不是没有错误-请参阅Dietrich的答案):
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;
}
在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)
最初尝试的特别错误:
- 需要使用
Detach
方法为out
赋值 - 需要连接到
in.parray
而不是*in.pparray
(不是一回事)
采用VARIANT参数的COM方法负责检查参数、捕获异常,并且它不会真正破坏[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;
}
Sideshow Bob和Roman R.的解决方案使用
ComVariant(out_sa).Detach(out);
这有一个严重的缺点。SAFEARRAY
out_sa
被传递给CComVariant's
构造函数,该构造函数将复制SAFEARRAY
。为了避免复制,最好使用
::VariantInit(out);
out->vt = (VT_ARRAY | VT_R8);
out->parray = out_sa.Detach();
正如Roman所指出的,您还应该从检查in
是否真的是VT_ARRAY | VT_R8
类型开始。Bob的解决方案有一个严重的错误:in.parray
附加到sa_in
,但没有分离,因此析构函数将销毁in.parray
。但是根据COM的规则,函数arraytimestwo(VARIANT in,...
不允许修改参数in
。COM充满陷阱。因此,我认为最好通过引用的方式传递参数in
。
我给出了一个(希望如此!)改进的解决方案和测试功能:
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)
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;
}
- OpenMP阵列性能较差
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 如何将三维尺寸不固定的三维阵列展平为一维阵列
- 当我的阵列太大时出现分段错误
- 位阵列上的快速AND运算
- 阵列必须使用大括号封闭的初始器进行初始化
- 两个 COM 组件中 ENUM 的重复条目
- COM 接口 c# 封送数组数组
- 没有从阵列<float>到阵列<int>的可行转换
- C++动态安全 2D 交错阵列
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- 将平面阵列重塑为复杂的特征类型
- 如何使用英特尔 PIN 捕获阵列的所有负载?
- 为什么我能够为阵列分配比计算机实际拥有的内存更多的内存
- 库特<<恩德尔;不适用于打印 2D 阵列
- 数组类 阵列的打印输出
- 如何读取 C++ SAFEARRAY**,该 SAFEARRAY** 是 COM 互操作的结果,其中 C# 返回值为
- 从较小的阵列到较大的阵列的元素级转换
- COM:访问冲突,使 BSTR 的安全阵列
- 通过COM发送和接收阵列