我最近遇到了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/