Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 访问COM对象中的不透明数据成员_C++_Com - Fatal编程技术网

C++ 访问COM对象中的不透明数据成员

C++ 访问COM对象中的不透明数据成员,c++,com,C++,Com,我最近在COM inproc服务器上遇到了一个问题 我有一个MCanvasFontCOM对象,它实现了ICanvasFont接口: ICanvasFont : public IUnknown { virtual HRESULT STDMETHODCALLTYPE Create( /* [in] */ BSTR bstrFamily, /* [in] */ double fSize) = 0; virtual HRESULT STDMETHODCA

我最近在COM inproc服务器上遇到了一个问题

我有一个
MCanvasFont
COM对象,它实现了
ICanvasFont
接口:

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::DrawText
方法访问
FontDelegate
对象的方法。最好的方法是什么?

也许我遗漏了什么。难道你不能简单地在MCanvasFont中将MCanvas声明为一个friend类,然后在MCanvas::DrawText中向下转换指向MCanvasFont的ICanvasFont指针吗

请注意,您正在使用的ICanvasFont指针可能不是MCanvasFont类型。如果将
dynamic_cast
用于向下播放,则仅当您收到的ICanvasFont指针来自与MCanvas实例相同的进程内服务器时,此操作才会成功。这是我能看到的唯一一种情况,你正在尝试做的事情甚至是可能的。但是,在尝试访问FontDelegate之前,您应该检测并验证您正在该上下文中操作

另一种方式似乎是从ICanvasFont转换为MCanvasFont

一种COM友好的方法是定义一个表示类“原样”的私有GUID:让MCanvasFont在其QI中通过返回一个非强制转换的“this”来响应它。然后,MCanvas可以使用带有此专用GUID的QI来检查ICanvasFont是否真的是MCanvasFont;如果QI成功,它现在可以使用正确铸造的MCanvasFont

这允许第三方代码以不透明COM对象的形式获取和传递从您处获得的对象,但当您获取自己的对象时,您可以确定它实际上是“您自己的对象”,然后适当地访问其内部

这种技术的好处是,它在不受支持的场景中会优雅地失败——您可以将其视为一种安全的COM样式转换,将您从不可知的COM世界带回C++世界:

如果第三方试图自己实现ICanvasFont,那么它当然会通过QI测试,因为他们不会实现私有GUID,因此您将知道拒绝它,这是适当的,因为听起来您的代码将此接口用作库功能的抽象,而不是扩展点

如果您收到的ICanvasFont是一个远程对象,QI将失败,因为COM远程处理基础结构将无法找到您的专用GUID的代理/存根信息,而且如果您在这种情况下不考虑提供远程处理或跨单元/多线程支持,这可能也是合适的



…或者,如果您有一个简单的GUI/STA风格的对象,希望在单个线程(单元)中使用,那么它至少可以这样工作。如果您允许在一个进程中将接口封送到不同的单元,那么您需要在上面的一般主题上做更多的工作,因为您实际上可能希望支持将源于另一个单元的ICanvasFont交给您。您仍然可以使用带有私有GUID的QI来询问对象是否是“您的一个”,但现在您需要QI到一个中间私有接口,该接口也具有编组支持,然后有一个方法可以通过隧道传输原始指针(并且,为了偏执,请检查对象是否处于同一进程中!);一旦您这样做了,您就需要意识到,从那时起,您将承担所有编组/线程化的责任。但是考虑到您问题的GUI风格,我猜这里可能不是这样。

这并不容易,至少在不违反COM原则的情况下是这样。为此,我通常编写一个方法,将
void*
返回到内部句柄,并将其隐藏到automation(我主要使用IDispatch对象,因此只要脚本客户端什么都看不到,脏接口就不会困扰我)。我也对不那么脏的东西感兴趣。为什么您需要从
MCanvas::DrawText
直接访问
MCanvasFont::fontdegate
?也许你应该改变你的设计,这样
MCanvas::DrawText
所需的
fontdegate
的功能就可以通过
ICanvasFont
接口的其他方法公开(这样你就可以在不违反COM原则的情况下,从
MCanvas::DrawText
调用这些方法)。@Alexandre C,是的,空虚的回归是我想到的第一件事。另一种方法似乎是从
ICanvasFont
转换为
MCAVASFONT
。但也许有更好的方法来做到这一点@_C64先生,我希望减少所有内部编译依赖项,并且不要将
fontdegate
声明为COM接口。
void*
方法的问题是它不利于编组。另一个选项是提供另一个接口
IFontDelegateProvider
,该接口可以在需要时处理
FontDelegate
的编组,并提供对
FontDelegate
对象或其方法的访问。恐怕这是最干净的解决方案了。COM是语言不可知的,您所操作的只是指向函数表的指针。没有安全的方法来贬低任何东西,因为你得到的实际的
ICanvasFont
可能是远程执行的某个对象的(自动生成的)代理。也许我在这里太愤世嫉俗了,但我一直认为所要求的本质上是后门黑客(见添加的评论)。为一般情况创建一个安全的解决方案显然是不可能的。被证明是错误的将是有趣的。
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;
};