c++ - 处理指向接口(interface)的指针的方法的正确实现

标签 c++ com vb6

我有一个用 C++ 实现的 COM 对象。我正在使用 VB6 应用程序中的这个对象。

问题是如何实现获取和返回接口(interface)指针的方法。 这是 IDL 的示例:

[...]
interface ICOMCvDC : IUnknown
{
    HRESULT GetPen([retval][out] ICOMCvPen** ppPen);
    HRESULT SetPen([in] ICOMCvPen* pPen);
};

下面是组件类对象的框架:

class COMCvDC : public ICOMCvDC
{
public:
    ...
    STDMETHODDECL GetPen(
        /* [retval][out] */ ICOMCvPen** ppPen);
    STDMETHODDECL SetPen(
        /* [in] */ ICOMCvPen* pPen);
    ...

protected:
    ICOMCvPen* m_pen;
};

...

STDMETHODIMP COMCvDC::GetPen(
    /* [retval][out] */ ICOMCvPen** ppPen)
{
    *ppPen = m_pen;
    return S_OK;
}

STDMETHODIMP COMCvDC::SetPen(
    /* [in] */ ICOMCvPen* pPen)
{
    m_pen = pPen;
    return S_OK;
}

我是 COM 的初学者,所以我不确定我的做法是否正确。我觉得我需要在某些接口(interface)指针上使用 QueryInterface 方法。了解 VB6 在解释如下代码时在做什么也很有趣:

Dim pen1 As ICOMCvPen
Set pen1 = dc1.GetPen()

是否在GetPen方法返回的接口(interface)指针上调用了AddRef方法?

更新1

我已经实现了两个测试对象(COMCvTest 和 COMCvTestFactory),它们只记录所有被调用的方法。然后我执行了以下 VB6 代码:

Dim test1 As ICOMCvTest
Set test1 = New COMCvTest
Debug.Print "Ref: " & test1.GetReferenceCounter
Set test1 = Nothing

下面是这些对象的生命周期日志:

COMCvTestFactory::COMCvTestFactory(); m_cRef = 1
COMCvTestFactory::QueryInterface() --- begin ---
    IID is {00000001-0000-0000-C000-000000000046}
    IID is IID_IClassFactory
    COMCvTestFactory::AddRef(); m_cRef = 2 (was 1)
COMCvTestFactory::QueryInterface() ---- end ----
COMCvTestFactory::Release(); m_cRef = 1 (was 2)
COMCvTestFactory::CreateInstance() --- begin ---
    COMCvTest::COMCvTest(); m_cRef = 1
    COMCvTest::QueryInterface() --- begin ---
        IID is {00000000-0000-0000-C000-000000000046}
        IID is IID_IUnknown
        COMCvTest::AddRef(); m_cRef = 2 (was 1)
    COMCvTest::QueryInterface() ---- end ----
    COMCvTest::Release(); m_cRef = 1 (was 2)
COMCvTestFactory::CreateInstance() ---- end ----
COMCvTest::AddRef(); m_cRef = 2 (was 1)
COMCvTest::Release(); m_cRef = 1 (was 2)
COMCvTestFactory::Release(); m_cRef = 0 (was 1); deleting object
COMCvTestFactory::~COMCvTestFactory()
COMCvTest::QueryInterface() --- begin ---
    IID is {00000000-0000-0000-C000-000000000046}
    IID is IID_IUnknown
    COMCvTest::AddRef(); m_cRef = 2 (was 1)
COMCvTest::QueryInterface() ---- end ----
COMCvTest::QueryInterface() --- begin ---
    IID is {9F660698-1950-4DE8-BB5F-C8D2D61F7367}
    IID is IID_ICOMCvTest
    COMCvTest::AddRef(); m_cRef = 3 (was 2)
COMCvTest::QueryInterface() ---- end ----
COMCvTest::QueryInterface() --- begin ---
    IID is {7FD52380-4E07-101B-AE2D-08002B2EC713}
    IID is IID_IPersistStreamInit
COMCvTest::QueryInterface() --- begin ---
    IID is {37D84F60-42CB-11CE-8135-00AA004BB851}
    IID is IID_IPersistPropertyBag
COMCvTest::Release(); m_cRef = 2 (was 3)
COMCvTest::Release(); m_cRef = 1 (was 2)
COMCvTest::GetReferenceCounter; m_cRef = 1
COMCvTest::Release(); m_cRef = 0 (was 1); deleting object
COMCvTest::~COMCvTest()

似乎 VB6 正在尝试从 COM 对象查询 IPersistStreamInitIPersistPropertyBag 接口(interface)。为什么?另外我不明白为什么在查询ICOMCvTest接口(interface)指针之前先查询IUnknown接口(interface)?

最佳答案

当然,QueryInterface() 使它成为一个干净的单行程序,它利用任何错误处理内置 QI 并处理您必须添加的引用计数:

STDMETHODIMP COMCvDC::GetPen(ICOMCvPen** ppPen)
{
    if (m_pen) return m_pen->QueryInterface(__uuidof(ICOMCvPen), (void**)ppPen);
    else {
        *ppPen = 0;
        return E_FAIL;
    }
}

STDMETHODIMP COMCvDC::SetPen(ICOMCvPen* pPen)
{
    if (m_pen) m_pen->Release();
    m_pen = pPen;
    return S_OK;
}

不要忘记在构造函数中将 m_pen 初始化为 NULL,并在析构函数中释放它。或者使用智能指针。

关于c++ - 处理指向接口(interface)的指针的方法的正确实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7646852/

相关文章:

c++ - 行内说明符

c++ - 从 IBuffer 获取 ComPtr<IStream>

windows - 禁止 MS-Office 应用程序以编程方式发送遥测数据

arrays - Visual Basic 6 数组作为参数

c++ - 函数调用如何给出编译时类型?

c++ - 组合和继承设计问题

c++ - 使用constexpr成员函数初始化constexpr成员变量

c# - 在 C# 中创建 COM 自动化服务器

vb.net - VB6 + VB.NET 失去焦点与验证?

delphi - 如何将 PChar 从 DLL 函数返回到 VB6 应用程序而不会有崩溃或内存泄漏的风险?