0

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

将被调用的类方法在 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. 在存储在 VARIANT(第二个参数)中的 SAFEARRAY 上使用 SafeArray(Un)AccessData 是否足够?

  5. 为了让这个东西正常工作(健壮),还有什么额外的事情需要考虑吗?

感谢您抽出宝贵的时间并可能帮助我!

ps:我已经得到了这个工作(或多或少)我只想避免我无法调试的问题(LEAKS!),因为调用应用程序是封闭源代码而不是在我的控制之下......

4

1 回答 1

1

您正在使用安全数组和输入/输出参数使您的喜好变得更加复杂。尤其是与您将要与之交互的古代 VB6 结合使用。

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

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

你会得到这样的:

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

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

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
于 2013-06-15T09:32:05.977 回答