0

在 c++ 中,我们可以通过设计返回 *this 的方法轻松地在类中设置方法链接。这在 ATL/COM 设置中是否可行?假设我有一个简单的 ATL 类 MyOBj。我想知道在这种情况下是否可以进行链接,如果可以,支持链接的方法的 idl 签名是什么?简单的例子将不胜感激!(实际上,我的方法是从 VBA 调用 excel 的,我希望在该 VBA 上下文中进行链接,因为我们已经为标准 VBA 方法进行了链接。)

多谢

R

编辑 :

在 .idl 文件中我有这个:

interface IRateModel : IDispatch{
    [id(1), helpstring("SETRATEMODEL")] HRESULT SETRATEMODEL( [in] VARIANT * var_in ) ;
    [id(2), helpstring("GETRATETERMSTRUCTURE")] HRESULT GETRATETERMSTRUCTURE( [in, out] VARIANT * var_in ) ;
};

interface IVolatilityModel : IDispatch{
    [id(1), helpstring("SETVOLATILITYMODEL")] HRESULT SETVOLATILITYMODEL( [in] VARIANT * var_in ) ;
    [id(2), helpstring("GETVOLATILITY")] HRESULT GETVOLATILITY( [in, out] VARIANT * var_in ) ;
};

interface IMyOption : IDispatch{
    [id(1), helpstring("SETMATURITY")] HRESULT SETMATURITY( [in] VARIANT * TheMaturity, [out,retval] IMyOption ** ret ) ;
    [id(2), helpstring("SETSTRIKE")] HRESULT SETSTRIKE( [in] VARIANT * TheStrike, [out,retval] IMyOption ** ret ) ;
    [id(3), helpstring("SETPAYOFF")] HRESULT SETPAYOFF( [in] VARIANT * ThePayoff, [out,retval] IMyOption ** ret ) ;
    [id(4), helpstring("ATTACHRATEMODEL")] HRESULT ATTACHRATEMODEL( [in] IRateModel ** TheRateModel, [out,retval] IMyOption ** ret ) ;
    [id(5), helpstring("ATTACHVOLATILITYPROCESS")] HRESULT ATTACHVOLATILITYPROCESS( [in] IVolatilityModel ** TheVolatilityModel, [out,retval] IMyOption ** ret ) ;
    [id(6), helpstring("PRICEIT")] HRESULT PRICEIT( [in, out] DOUBLE * price ) ;
};

SETRATEMODEL 的实现是:

STDMETHODIMP CRateModel::SETRATEMODEL( /*[in]*/ VARIANT * var_in )
{
    // something
    // ...

    return S_OK ;
}

自从我添加了其他接口以来,这个实现没有改变。在添加它们之前,在调试时,VARIANT 是 VT_R8(来自 vba VARIANT,这个来自 excel 的 double)现在在调试时,变体是 VT_DISPATCH。

PS:我是 ATL/COM 的新手。

4

3 回答 3

2

像这样的东西:

interface IMyInterface {
  HRESULT DoSomething([in] long someParam, [out, retval] IMyInterface** ret);
  HRESULT DoSomethingElse([out, retval] IMyInterface** ret);
};

脚本客户端应该能够做到myObj.DoSomething(42).DoSomethingElse()

于 2013-09-14T18:49:36.450 回答
0

好的,#VALUE!是在函数 calcmodule11 中引起的,因为作为 VARIANT 传递给它的是“VARIANT/Object/Range”,其 value2 组件是 VARIANT/double,并且我没有在 MyVARIANT 包装类中处理 VARIANT/Object/Range。但是如果你通过 x.value2 (在 vba 中)做这个方法,一切都很好。这也解释了为什么技巧 dim xx 作为变体,xx = x 函数:这样做以某种方式将 x.value2 放入 xx,但我不知道为什么......对于#VALUE!在涉及方法链接的 VBA 函数中,原因是相同的,只是 VARIANT 更加复杂:指向 com obj 实例的指针......

因此,我将不得不重写/完成我的 MyVARIANT 类以处理将出现的所有 VT_DISPATCH 情况,如“VARIANT/Object/Range”,但也更复杂的其他 VT_DISPATCH'es...

于 2013-09-17T20:52:15.807 回答
0

在 Igor Tandetnik 第一个回答之后,我尝试了以下 ATL/COM 的链接方法,在名为“Complex”的简单 ATL/COM 对象中,对复数进行建模:

在 IDL 文件中:

[id(1), helpstring("SET")] HRESULT SET( [in/*,out*/] VARIANT * var_inx, [in/*,out*/] VARIANT * var_iny ) ;
[id(2), helpstring("SETREALPART")] HRESULT SETREALPART( [in] VARIANT * var_inx, [out, retval] IComplex** ret ) ;
[id(3), helpstring("SETIMAGPART")] HRESULT SETIMAGPART( [in] VARIANT * var_iny, [out, retval] IComplex** ret ) ;
[id(4), helpstring("MODULE")] HRESULT MODULE( [out, retval] VARIANT * var_out ) ;

在 Complex.h 文件中:

class ATL_NO_VTABLE CComplex :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CComplex, &CLSID_Complex>,
    public IDispatchImpl<IComplex, &IID_IComplex, &LIBID_ATLSimpleChainingTestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
    CComplex() ;
    CComplex( double x, double y ) ;
    CComplex & setRealPart( double x );
    CComplex & setImagPart( double y );
    void setRealPart2( double x );
    void setImagPart2( double y );
    double getRealPart( void ) ;
    double getImagPart( void ) ;
    double getModule( void ) ;

private:

    double _RealPart ;
    double _ImagPart ;

public:
DECLARE_REGISTRY_RESOURCEID(IDR_COMPLEX)


BEGIN_COM_MAP(CComplex)
    COM_INTERFACE_ENTRY(IComplex)
    COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()



    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:

    STDMETHOD( SET )( /*[in]*/ VARIANT * var_inx, /*[in]*/ VARIANT * var_iny ) ;
    STDMETHOD( SETREALPART )( /*[in]*/ VARIANT * var_inx, /*[out, retval]*/ IComplex** ret ) ;
    STDMETHOD( SETIMAGPART )( /*[in]*/ VARIANT * var_iny, /*[out, retval]*/ IComplex** ret ) ;
    //STDMETHOD( SETREALPART )( /*[in]*/ VARIANT * var_inx ) ;
    //STDMETHOD( SETIMAGPART )( /*[in]*/ VARIANT * var_iny ) ;
    STDMETHOD( MODULE )( /*[out, retval]*/ VARIANT * var_out ) ;
};

OBJECT_ENTRY_AUTO(__uuidof(Complex), CComplex)

在 Complex.cpp 文件中:

// Complex.cpp : CComplex 的实现

#include "stdafx.h"
#include "Complex.h"
#include <cmath>
#include "MYVARIANT.h"

// CComplex

CComplex::CComplex( void )
{

}

CComplex::CComplex( double x, double y )
{
    _RealPart = x ;
    _ImagPart = y ;
}

CComplex & CComplex::setRealPart( double x )
{
    _RealPart = x ;
    return *this ;
}

void CComplex::setRealPart2( double x )
{
    _RealPart = x ;
}

CComplex & CComplex::setImagPart( double y )
{
    _ImagPart = y ;
    return *this ;
}

void CComplex::setImagPart2( double y )
{
    _ImagPart = y ;
}

double CComplex::getRealPart( void )
{
    return _RealPart ;
}

double CComplex::getImagPart( void )
{
    return _ImagPart ;
}

double CComplex::getModule( void )
{
    return std::sqrt( _RealPart*_RealPart + _ImagPart*_ImagPart ) ;
}

STDMETHODIMP CComplex::SET( /*[in]*/ VARIANT * var_inx, /*[in]*/ VARIANT * var_iny )
{
    MyVARIANT myvarx( var_inx ) ;
    MyVARIANT myvary( var_iny ) ;
    if ( myvarx.GETNBLINES()*myvarx.GETNBCOLS()*myvary.GETNBLINES()*myvary.GETNBCOLS() != 1L )
        return E_INVALIDARG ;
    ATL::CComVariant myccomvarx ;
    ATL::CComVariant myccomvary ;
    myvarx.GET(0, 0, myccomvarx ) ;
    myvary.GET(0, 0, myccomvary ) ;
    if ( ( myccomvarx.vt != VT_R8 ) || ( myccomvary.vt != VT_R8 ) )
        return E_INVALIDARG ;
    setRealPart2( myccomvarx.dblVal ) ;
    setImagPart2( myccomvary.dblVal ) ;
    return S_OK ;
}

STDMETHODIMP CComplex::SETREALPART( /*[in]*/ VARIANT * var_inx, /*[out, retval]*/ IComplex** ret )
//STDMETHODIMP CComplex::SETREALPART( /*[in]*/ VARIANT * var_inx  )
{
    MyVARIANT myvarx( var_inx ) ;
    if ( myvarx.GETNBLINES()*myvarx.GETNBCOLS() != 1L )
        return E_INVALIDARG ;
    ATL::CComVariant myccomvarx ;
    myvarx.GET(0, 0, myccomvarx ) ;
    if ( myccomvarx.vt != VT_R8 )
        return E_INVALIDARG ;
    setRealPart2( myccomvarx.dblVal ) ;
    return S_OK ;
}

STDMETHODIMP CComplex::SETIMAGPART( /*[in]*/ VARIANT * var_iny, /*[out, retval]*/ IComplex** ret )
//STDMETHODIMP CComplex::SETIMAGPART( /*[in]*/ VARIANT * var_iny  )
{
    MyVARIANT myvary( var_iny ) ;
    if ( myvary.GETNBLINES()*myvary.GETNBCOLS() != 1L )
        return E_INVALIDARG ;
    ATL::CComVariant myccomvary ;
    myvary.GET(0, 0, myccomvary ) ;
    if ( myccomvary.vt != VT_R8 )
        return E_INVALIDARG ;
    setImagPart2( myccomvary.dblVal ) ;
    return S_OK ;
}

STDMETHODIMP CComplex::MODULE( /*[out, retval]*/ VARIANT * var_out )
{
    double mod = getModule() ;
    MyVARIANT module( &mod, 1, 1) ;
    module.ATTACH( var_out ) ;
    return S_OK ;
}

//

MyVARIANT 是一个 VARIANT 包装类,可以完美运行并且经过全面回测。在

ATL::CComVariant myccomvarx ;
myvarx.GET(0, 0, myccomvarx ) ;

GET 用 MyVARIANT myvarx 的系数 (0,0) 填充 ATL::CComVariant myccomvarx。

很容易猜到是什么

GETNBLINES()

GETNBCOLS()

方法正在做。在

MyVARIANT module( &mod, 1, 1) ;
module.ATTACH( var_out ) ;

方法 ATTACH 用构造函数构造的 MyVARIANT“模块”“填充”VARIANT var_out

MyVARIANT( double *, long, 1)

它将(在这种情况下) MyVARIANT 与指向 double 的指针相关联。让我再说一遍,MyVARIANT 已经过充分的回测,并且完全有效。

现在,在 VBA for Excel 方面,我创建了以下六个函数:

Function calcmodule11(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    Call z.SET(x, y)
    calcmodule11 = z.module()

End Function

Function calcmodule12(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    Dim xx As Variant
    xx = x
    Dim yy As Variant
    yy = y
    Call z.SET(xx, yy)
    calcmodule12 = z.module()

End Function

Function calcmodule21(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    z.SETREALPART (x)
    z.SETIMAGPART (y)
    calcmodule21 = z.module()

End Function

Function calcmodule22(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    Dim xx As Variant
    xx = x
    Dim yy As Variant
    yy = y
    z.SETREALPART (xx)
    z.SETIMAGPART (yy)
    calcmodule22 = z.module()

End Function

Function calcmodule31(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    z.SETREALPART(x).SETIMAGPART (y)
    calcmodule31 = z.module()

End Function

Function calcmodule32(ByRef x As Variant, ByRef y As Variant) As Variant

    Dim z As ATLSimpleChainingTestLib.Complex
    Set z = New ATLSimpleChainingTestLib.Complex
    Dim xx As Variant
    xx = x
    Dim yy As Variant
    yy = y
    Call z.SETREALPART(x).SETIMAGPART(y)
    calcmodule32 = z.module()

End Function

我在 excel 单元格中调用了这六个函数 F(即 F 等于 calcmodule11 或 calcmodule12 或...等),编写

=F(B3,B4)

其中,B3 和 B4 是两个 excel 单元格,每个单元格都包含双 1。以下是每个函数获得的结果:

calcmodule11 #值!calcmodule12 1.414213562 calcmodule21 1.414213562 calcmodule22 #VALUE!calcmodule31 #值!calcmodule32 #值!

1.414213562 确实是预期的正确值。

问题 :

1)为什么我有一个#VALUE!调用 calcmodule11 ?

2)由于 calcmodule12 给出了正确的值而 calcmodule11 没有,我希望这对(calcmodule21,calcmodule22)有相同的行为,但事实恰恰相反:calcmodule21 给出了正确的值,而 calcmodule22 没有。为什么 ?

2) 正如 Igor Tandetnik 解释它对我的问题的第一个答案,我将方法链接放在函数 calcmodule31 和 calcmodule32 中。而且它不起作用,它在 calcmodule21 和 calcmodule22 的情况下工作,至少对于 calcmodule21。为什么 ?

Igor Tandetnik,正如我完全按照您对我的建议(如果我错了,请纠正我),为什么它不起作用?...

多谢。

于 2013-09-16T21:10:34.487 回答