如何在基于ATL的服务器中正确转换和使用本机COM类型?

时间:2013-06-14 09:16:30

标签: c++ com vb6 atl

我必须编写一个由插件接口调用的COM服务器DLL(使用ATL) 一个旧的(闭源)VB6应用程序,并希望避免 可能的泄漏(当然)!接口描述按原样给出,不能 不幸的是改变了:

将在VB端声明要调用的类方法,如下所示:

Public Function Process(data As Object,
                        Params As Variant,
                        Results() As Single) As Integer

IDL中的接口声明如下:

[id(1)] HRESULT Process([in,out] IDispatch**       pDataIDisp,
                        [in,out] VARIANT*          pParamsVar,
                        [in,out] SAFEARRAY(FLOAT)* pResSA,
                        [out,retval] SHORT*        pRetVal);

最后调用的代码如下所示:

STDMETHODIMP Analyzer::Process(IDispatch** pDataIDisp,
                               VARIANT*    pParamsVar,
                               SAFEARRAY** pResSA,
                               SHORT*      pRetVal)
{
    try
    {
        // Prepare for access
        CComPtr<IDispatch> dataComPtr = *pDataIDisp;

        // VARTYPE from caller is VT_VARIANT | VT_ARRAY | VT_BYREF;
        CComVariant prms = *pParamsVar;               // OR use .Attach ?
        CComSafeArray<VARIANT> prmsArr = prms.parray; // OR use prms.Attach ?

        // SafeArray is FADF_HAVEVARTYPE
        CComSafeArray<FLOAT> res = *pResSA; // OR use res.Attach(pResSA*) ?

        {
            // Use ATL types wrapped from above
        }

        // Cleanup ????
        .
        .
        .
    }
    catch (...) {}
    return S_OK;
}

我想知道的是:

  1. 我的接受(和转换)参数的方法是ATL 键入正确的用法还是有另一种(更好的?)方式?

  2. 我是否必须在IDispatch *上自行调用AddRef()和/或Release()或 是否足以分配给CComPtr来完成这一切?

  3. 作为VT_BYREF给出的第二个参数的含义是什么?

    头文件说:

    *  VT_VARIANT          [V][T][P][S]  VARIANT *
    *  VT_ARRAY            [V]           SAFEARRAY*
    *  VT_BYREF            [V]           void* for local use
    

    我不清楚......#-o

  4. 在存储的SAFEARRAY上使用SafeArray(Un)AccessData就足够了 VARIANT(第二个参数)?

  5. 要使这件事能正常运行(强健)还需要考虑哪些其他事项?

  6. 感谢您抽出宝贵时间并帮助我!

    ps:我已经开始工作(或多或少)我只想避免问题(泄漏!)    我不能    调试,因为调用应用程序是封闭源代码而不是我的控制......

1 个答案:

答案 0 :(得分:1)

你正在使用安全数组和输入/输出参数使你真正的编译。特别是与古老的VB6结合使用时,您将接口。

有一些简单的规则可以使其清晰,简单和可靠:

  • [in][out][out, retval]个参数;在你的代码片段中,你使用[in, out]而没有任何显示的意图来实际更改值以利用out说明符:当你没有特殊的理由时,它只会使C ++方面变得复杂,并且额外的引用级别增加了错误
  • 参数中的
  • 不需要附加到C ++类并发布
  • 当你从C ++方法返回时,为out参数留下一个值你通常从持有者C ++类中分离()接口指针,字符串,变体和安全数组 - 将所有权从内部类转移到调用者释放资源的义务
  • 而不是直接在IDL上使用安全数组并尝试匹配VB端的信号,我建议使用变体:你总是可以将数组放入变体中,包括变体数组,VB6将能够回滚< / LI>
  • out而不是retval参数在VB6端为ByRef,参数将由ByVal

你会这样:

[id(1)] HRESULT Process([in] IDispatch* pDataIDisp,
                        [in] VARIANT pParamsVar,
                        [out, retval] VARIANT* pvResult);

在C ++服务器端,您只能读取参数,不需要释放。您将使用ATL CComVariant和朋友在C ++中完全构建它来初始化输出变量,然后在处理的最后阶段将其分离。

Public Function Process(data As Object,
                        Params As Variant) As Object
' ...
Dim Data, Params As Object
' ...
Dim Result As Object
Result = Server.Process(Data, Params)
' NOTE: Result is OK to be an array