0

I'm trying to call a registered COM interface (Inproc dll) in an Eclipse C++ environment (MinGW GCC toolchain). I therefore don't believe that I can simply import the dll typelib the way I typically would in Visual C++. I'm trying to define the interface myself to simplify the function calls rather than using Invoke.

The IDL for the interface out of oleview looks like:

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

I've attempted to define the interface in my own header file like this:

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;

};

This appears to work well for the method calls but not for the properties. When I attempt to call any of the property functions, I get access violations. It does however seem to work if I use something like

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

Does that make sense? Is there a better way to declare the properties for the COM interface so that I can use them like normal properties?

forother
  • 39
  • 4
  • COM properties are backed by "normal" methods, one getter and one setter. Some clients (e.g. scripting languages) can wrap syntactic sugar around those method calls to make them look like real properties, but that's all an illusion. The underlying methods do indeed look the way you show; you are on the right track. – Igor Tandetnik Nov 05 '19 at 21:10
  • Now, can't you compile your IDL with MIDL compiler? One of its outputs is an .h file that looks very similar to the one you are handcrafting. – Igor Tandetnik Nov 05 '19 at 21:11
  • @IgorTandetnik scripting languages typically go through `IDispatch::GetIDsOfNames()` and `IDispatch::Invoke()`, they don't access the property getter/setter methods directly. So, when a script accesses `obj.Prop` or calls `obj.Method()`, it is actually calling `obj.GetIDsOfNames()` to get the DispID of `Prop` or `Method` (raising an error if the DispID can't be found) and then calling `obj.Invoke()` with that DispID and appropriate flags and parameters as needed. – Remy Lebeau Nov 05 '19 at 21:25
  • I'd hint that if you're going to call from C++, look at the interface output and not the dispinterface output in OLEVIEW. The interface will be categorized as dispinterface and interface, but the one you want to use ins in the interface section. – Joseph Willcoxson Nov 05 '19 at 21:57
  • Brr. It is a dispinterface, that means that clients are expected to call these members through IDispatch. The server has no obligation to make it work when you ignore that and call them directly. Which ought to be easier to get going through Eclipse, just a lot of grungy code. – Hans Passant Nov 05 '19 at 22:29

1 Answers1

0

Usually, C++ interfaces are something like:

STDMETHOD(get_BracketType)(BracketType* BType);

STDMETHOD(put_BrackedType)(BracketType Btype);

Properties are generally going to have HRESULT return types... just like methods. They'll have a get_ or put_ prefix in front of the property name.

Not sure how the Eclipse C++ environment does this.

Joseph Willcoxson
  • 5,853
  • 1
  • 15
  • 29