我最近遇到了COM Inproc服务器问题。

我有一个实现MCanvasFont接口(interface)的ICanvasFont COM对象:

ICanvasFont : public IUnknown
{
    virtual HRESULT STDMETHODCALLTYPE Create(
        /* [in] */ BSTR bstrFamily,
        /* [in] */ double fSize) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetSize(
        /* [retval][out] */ double fSize) = 0;
};
MCanvasFont对象包含一个指向FontDelegate对象的不透明指针,该对象实现了实际的字体操作:
class MCanvasFont : public ICanvasFont
{
public:
    MCanvasFont();
    virtual ~MCanvasFont();

    virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppv);
    virtual ULONG   STDMETHODCALLTYPE AddRef();
    virtual ULONG   STDMETHODCALLTYPE Release();

    virtual HRESULT STDMETHODCALLTYPE Create(
        /* [in] */ BSTR bstrFamily,
        /* [in] */ double fSize);

    virtual HRESULT STDMETHODCALLTYPE SetSize(
        /* [in] */ double fSize);

protected:
    class FontDelegate;
    const std::unique_ptr<FontDelegate> m_font; // opaque pointer

    // Reference count
    long m_cRef;
};

还有一个实现MCanvas接口(interface)的ICanvas类。 ICanvas接口(interface)具有用于设置当前字体的SetFont(ICanvasFont* pFont)抽象方法和用于在 Canvas 上绘制文本的DrawText方法:
class MCanvas : public ICanvas
{
public:
    MCanvas();
    virtual ~MCanvas();

    virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppv);
    virtual ULONG   STDMETHODCALLTYPE AddRef();
    virtual ULONG   STDMETHODCALLTYPE Release();

    STDMETHODDECL GetFont(
        /* [retval][out] */ ICanvasFont** ppFont);
    STDMETHODDECL SetFont(
        /* [in] */ ICanvasFont* pFont);

    // ...

    STDMETHODDECL DrawText(
        /* [in] */ double x,
        /* [in] */ double y,
        /* [in] */ BSTR text);

protected:
    COMAutoPtr<ICanvasPen>     m_pen;
    COMAutoPtr<ICanvasBrush>   m_brush;
    COMAutoPtr<ICanvasFont>    m_font;

    // Reference count
    long m_cRef;
};

我需要一种从FontDelegate方法访问MCanvas::DrawText对象的方法。最好的方法是什么?

最佳答案



一种实现COM友好的方式是定义一个私有(private)GUID,它表示您的类“按原样”:让MCanvasFont通过返回未广播的“this”以其QI对其进行响应。然后,MCanvas可以使用带有此专用GUID的QI来检查ICanvasFont是否确实是MCanvasFont;如果QI成功,则现在可以正常播放MCanvasFont。

这使第三方代码可以获取和传递从您那里获得的对象,它们是不透明的COM对象,但是当您获得自己的对象之一时,您可以确定它实际上是“自己的对象”,然后适当地访问其内部。

该技术的好处是,在不受支持的情况下,它会正常失败-您可以将其视为一种安全的COM样式强制转换,它可以使您从COM不可知论的世界回到C++的世界:

如果第3方尝试自己实现ICanvasFont,则由于他们将不实现私有(private)GUID,因此它当然会通过QI测试,因此您会知道拒绝它是适当的,因为听起来您的代码是使用此接口(interface)作为库功能的抽象,而不是作为扩展点。

如果您收到的ICanvasFont是一个远程对象,则QI会失败,因为COM远程处理基础结构将无法找到您的私有(private)GUID的代理/存根信息,如果您不想提供远程处理,那么这很可能是合适的或在这种情况下跨部门/多线程支持。

...或者至少这是如果您有一个简单的GUI / STA风格的对象,该对象希望在单个线程(公寓)中使用的话,它将如何工作。如果允许在一个过程中将接口(interface)编码到不同的单元,则您需要对上述一般主题做更多的工作,因为您实际上可能希望支持将源于其他单元的ICanvasFont移交给其他单元。您仍然可以将QI与私有(private)GUID一起使用,以询问对象是否“属于您的对象”,但是现在您需要QI到也具有编码支持的中间私有(private)接口(interface),然后有一种方法可以隧道原始指针通过(并且,出于偏执狂,检查对象是否在同一进程中!);并且一旦这样做,您就需要意识到自己将承担所有的编码/线程任务。但是考虑到您的问题的GUI风格性质,我猜测这里可能不是这种情况。

关于c++ - 访问COM对象中的不透明数据成员,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10790784/

10-12 07:33
查看更多