English 中文(简体)
正确执行处理接口点的方法
原标题:A correct implementation of the methods that deal with a pointer to an interface
  • 时间:2011-10-04 11:00:25
  •  标签:
  • c++
  • com
  • vb6

我有一个共同点,在C++实施。 我正在使用VB6申请中的这个物体。

The question is how to implement a methods that get and return a pointer to an interface. Here is the sample of an IDL:

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

下面是部件类别物体的kel:

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;
}

我是执委会的开端人,因此,如果我这样做是正确的,我就不放心。 我感到,我需要使用<条码>中某些接口器的QueryInterface方法。 了解VB6在解释守则时正在做些什么也是令人感兴趣的:

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

它是否将<代码>AddRef方法称作通过<代码>GetPen方法回归的接口点?

Update 1

我已实施了两个试验目标(COMCv 和COMCv 试验场),这些试验目标只是标出所有所谓的方法。 接着,我执行以下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一样,它试图查询IPersistStreamInitIPersistPropertyBag来自COM标的接口。 为什么? 另外,我不理解为什么在查询<代码>ICOMCv《<<<<<>>>>> 代码>接口之前出现查询?

问题回答

Sure, Query Interface () is it a Clean one-liner, which take接手在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;
}

Don tabes开始将m_pen to NUL in the Constructionor and release it in the destructor. 或者使用智能点。

除了一件事外,与接口管理没有什么特殊之处:你必须照顾到Addref/release电话。 正因为如此,强烈建议使用精炼点器包裹进行自我管理(C++ pseudo-code):

CComPtr<ICOMCvPen> m_pen;

HRESULT Get(IPen** ppPen) { ... *ppPen = CComPtr<ICOMCvPen>(m_pen).Detach();  ... }
HRESULT Set(IPen* pPen) { ... m_pen = pPen;  ... }

And that s it! If you don t use CComPtr, you have to do "if(!x) x->Release()" stuff all the way and it s so easy to make a mistake.

Re: Update 1

  • IUnknown might be queried first if IID_IUnknown was the argument in VB6 s CoCreateInstance; then it QueryInterface d the interface of interest.
  • a query for IPersistStreamInit and IPersistPropertyBag is perhaps a part of standard object initialization with VB6 runtime; should this object be loaded with the form, it could be initialized from persistent data.

还指出,在初始化时,某些接口通常会与物体权相脱节,以便它们在需要以后随时备妥,如需要再利用。





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签