通过COM发送和接收阵列 [英] Sending and receiving arrays over 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屋!