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



我必须写一个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()吗分配一台计算机来完成这一切是否足够?

  3. 第二个参数VT_BYREF的含义是什么?

    头文件说:

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

    我不清楚....# - o

  4. 是否足以使用SafeArray(Un)AccessData上存储的SafeArray变体(第二个参数)?

  5. 要想让这个东西正常工作(健壮),还有什么需要考虑的吗?

谢谢你花时间帮助我!

ps:我已经得到了这个工作(或多或少),我只想避免问题(泄漏!)我不能调试作为调用应用程序是闭源的,不在我的控制之下…

您正在使用安全数组和in/out参数进行真正的编译。特别是与古老的VB6相结合,你将与。

有几个简单的规则使它更清晰、更容易和可靠:

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

你会得到这样的结果:

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

在c++服务器端,你只需要从in参数中读取,不需要释放。您将通过使用ATL CComVariant和friends完全在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

最新更新