【问题标题】:How to declare COM interface with properties in C++如何在 C++ 中声明具有属性的 COM 接口
【发布时间】:2020-03-02 07:06:12
【问题描述】:

我正在尝试在 Eclipse C++ 环境(MinGW GCC 工具链)中调用已注册的 COM 接口(Inproc dll)。因此,我不相信我可以像在 Visual C++ 中通常那样简单地导入 dll 类型库。我正在尝试自己定义接口以简化函数调用,而不是使用 Invoke。

oleview 外接口的 IDL 如下所示:

  uuid(9293C753-B073-11D2-BD89-0060978EEB9C),
  helpstring("IXSequence Interface"),
  dual
]
dispinterface IXSequence {
    properties:
    methods:
        [id(0x00000001), helpstring("method Close")]
        void Close();
        [id(0x00000002), helpstring("method New")]
        void New();
        [id(0x00000003), helpstring("method Open")]
        void Open(
                        BSTR FileName, 
                        long ReadOnly);
        [id(0x00000004), helpstring("method Save")]
        void Save(
                        BSTR UserName, 
                        BSTR Comment, 
                        long Overwrite);
        [id(0x00000005), helpstring("method SaveAs")]
        void SaveAs(
                        BSTR FileName, 
                        BSTR UserName, 
                        BSTR Comment, 
                        long Overwrite);
        [id(0x00000006), propget, helpstring("property Header")]
        VARIANT Header();
        [id(0x00000007), propget, helpstring("property AuditDataCollection")]
        VARIANT AuditDataCollection();
        [id(0x00000008), propget, helpstring("property Samples")]
        VARIANT Samples();
        [id(0x00000009), propget, helpstring("property BracketType")]
        XBracketTypes BracketType();
        [id(0x00000009), propput, helpstring("property BracketType")]
        void BracketType([in] XBracketTypes rhs);
        [id(0x0000000a), propget, helpstring("property UserLabel")]
        BSTR UserLabel(short Index);
        [id(0x0000000a), propput, helpstring("property UserLabel")]
        void UserLabel(
                        short Index, 
                        [in] BSTR rhs);
        [id(0x0000000b), propget, helpstring("property TrayConfiguration")]
        BSTR TrayConfiguration();
        [id(0x0000000b), propput, helpstring("property TrayConfiguration")]
        void TrayConfiguration([in] BSTR rhs);
        [id(0x0000000c), propget, helpstring("property FileName")]
        BSTR FileName();
        [id(0x0000000d), propget, helpstring("property NewFile")]
        long NewFile();
};

我尝试在自己的头文件中定义接口,如下所示:

const GUID CLSID_XcalFiles = { 0x9293C754, 0xB073, 0x11D2, {0xBD, 0x89, 0x00, 0x60, 0x97, 0x8E, 0xEB, 0x9C } };
const IID IID_IXSequence = { 0x9293C753, 0xB073, 0x11D2, {0xBD, 0x89, 0x00, 0x60, 0x97, 0x8E, 0xEB, 0x9C } };

typedef enum {
    XUnspecified = 0,
    XOverlapped = 1,
    XNonBracketed = 2,
    XNonOverlapped = 3,
    XOpen = 4
} XBracketTypes;

enum XSampleTypes
{
    XSampleUnknown = 0,
    XSampleBlank = 1,
    XSampleQC = 2,
    XSampleStdClear = 3,
    XSampleStdUpdate = 4,
    XSampleStdBracket = 5,
    XSampleStdBracketStart = 6,
    XSampleStdBracketEnd = 7,
    XSampleProgram = 8,
    XSampleNumbersOfDifferentTypes = 9
};

DECLARE_INTERFACE_(IXSequence, IDispatch)
{
//methods
    STDMETHOD_(void, Close)(THIS)PURE;
    STDMETHOD_(void, New)(THIS)PURE;
    STDMETHOD_(void, Open)(THIS_ BSTR FileName, long ReadOnly)PURE;
    STDMETHOD_(void, Save)(THIS_ BSTR UserName, BSTR Comment, long Overwrite)PURE;
    STDMETHOD_(void, SaveAs)(THIS_ BSTR FileName, BSTR UserName, BSTR Comment, long Overwrite)PURE;
    STDMETHOD_(VARIANT, GetHeader)(THIS)PURE;
    STDMETHOD_(VARIANT, GetAuditDataCollection)(THIS)PURE;
    STDMETHOD_(VARIANT, GetSamples)(THIS)PURE;
//properties
    STDMETHOD_(XBracketTypes, BracketType)(THIS)PURE;
    STDMETHOD_(void, BracketType)(THIS_ XBracketTypes rhs)PURE;
    STDMETHOD_(BSTR, UserLabel)(THIS_ short Index)PURE;
    STDMETHOD_(void, UserLabel)(THIS_ short Index, BSTR rhs)PURE;
    STDMETHOD_(BSTR, TrayConfiguration)(THIS)PURE;
    STDMETHOD_(void, TrayConfiguration)(THIS_ BSTR rhs)PURE;
    STDMETHOD_(BSTR, FileName)(THIS)PURE;
    STDMETHOD_(long, NewFile)(THIS)PURE;

};

这似乎适用于方法调用,但不适用于属性。当我尝试调用任何属性函数时,我会遇到访问冲突。但是,如果我使用类似的东西,它似乎确实有效

STDMETHOD(GetBracketType)(THIS_ XBracketTypes* rhs)PURE;

这有意义吗?有没有更好的方法来声明 COM 接口的属性,以便我可以像使用普通属性一样使用它们?

【问题讨论】:

  • COM 属性由“普通”方法支持,一个 getter 和一个 setter。一些客户端(例如脚本语言)可以在这些方法调用周围包装语法糖,使它们看起来像真正的属性,但这都是一种错觉。底层方法确实看起来像你展示的那样;你在正确的轨道上。
  • 现在,你不能用 MIDL 编译器编译你的 IDL 吗?它的输出之一是一个看起来与您正在手工制作的文件非常相似的 .h 文件。
  • @IgorTandetnik 脚本语言通常通过IDispatch::GetIDsOfNames()IDispatch::Invoke(),它们不直接访问属性getter/setter 方法。所以,当一个脚本访问obj.Prop或调用obj.Method()时,实际上是调用obj.GetIDsOfNames()获取PropMethod的DispID(如果找不到DispID则报错)然后调用obj.Invoke() 根据需要使用该 DispID 以及适当的标志和参数。
  • 我会提示,如果您要从 C++ 调用,请查看接口输出,而不是 OLEVIEW 中的调度接口输出。接口将分为dispinterface和interface,但是你要在interface部分使用ins。
  • 老兄。它是一个调度接口,这意味着客户端需要通过 IDispatch 调用这些成员。当您忽略它并直接调用它们时,服务器没有义务使其工作。这应该更容易通过 Eclipse,只是很多蹩脚的代码。

标签: c++ interface com idispatch


【解决方案1】:

通常,C++ 接口类似于:

STDMETHOD(get_BracketType)(BracketType* BType);

STDMETHOD(put_BrackedType)(BracketType Btype);

属性通常会有 HRESULT 返回类型......就像方法一样。它们的属性名称前会有一个 get_ 或 put_ 前缀。

不确定 Eclipse C++ 环境是如何做到这一点的。

【讨论】:

  • 如果是双接口的话,上面应该可以工作。如果不是双接口,就得使用Invoke。
猜你喜欢
  • 1970-01-01
  • 2017-08-22
  • 2020-10-30
  • 2020-04-29
  • 2015-03-04
  • 2011-02-26
  • 1970-01-01
  • 2010-09-24
  • 2015-12-29
相关资源
最近更新 更多