简体   繁体   中英

Win32 COM Programming in Plain C

How can I properly implement multiple COM interfaces using plain C? If we look at the CommonFileDialog sample , we will see that the declaration of the event handler is like this:

class CDialogEventHandler : public IFileDialogEvents,
                            public IFileDialogControlEvents
{...};

The class implements the methods of IFileDialogEvents and IFileDialogControlEvents . Which will be the correct vTable for CDialogEventHandler and how should I implement QueryInterface in C? I know that it is much more appropriate to use C++, but I need to do it in C.

The code that worked for me:

typedef struct CDialogEventHandler
{
    const IFileDialogEventsVtbl* lpVtbl1;
    const IFileDialogControlEventsVtbl* lpVtbl2;
    long _cRef;
}CDialogEventHandler;

// IUnknown methods
IFACEMETHODIMP QueryInterface_IFileDialogEvents(IFileDialogEvents* this, REFIID riid, void** ppv)
{
    static const QITAB qit[] = 
    {
        QITABENT(CDialogEventHandler, IFileDialogEvents),
        {&IID_IFileDialogControlEvents, sizeof(void*)},
        { 0 }
    };
    HRESULT hr = QISearch(this, qit, riid, ppv);
    if (SUCCEEDED(hr)) this->lpVtbl->AddRef(this);
    return hr;
}

IFACEMETHODIMP_(ULONG) AddRef_IFileDialogEvents(IFileDialogEvents* this)
{
    return InterlockedIncrement(&(((CDialogEventHandler*)this)->_cRef));
}

IFACEMETHODIMP_(ULONG) Release_IFileDialogEvents(IFileDialogEvents* this)
{
    long cRef = InterlockedDecrement(&(((CDialogEventHandler*)this)->_cRef));
    if (!cRef) free(this);
    return cRef;
}

IFACEMETHODIMP QueryInterface_IFileDialogControlEvents(IFileDialogControlEvents* this, REFIID riid, void** ppv)
{
    this = ((BYTE*)this) - sizeof(void*);
    static const QITAB qit[] = {
        QITABENT(CDialogEventHandler, IFileDialogEvents),
        {&IID_IFileDialogControlEvents, sizeof(void*)},
        { 0 }
    };
    HRESULT hr = QISearch(this, qit, riid, ppv);
    if (SUCCEEDED(hr)) this->lpVtbl->AddRef(this);
    return hr;
}

IFACEMETHODIMP_(ULONG) AddRef_IFileDialogControlEvents(IFileDialogControlEvents* this)
{
    this = ((BYTE*)this) - sizeof(void*);
    return InterlockedIncrement(&(((CDialogEventHandler*)this)->_cRef));
}

IFACEMETHODIMP_(ULONG) Release_IFileDialogControlEvents(IFileDialogControlEvents* this)
{
    this = ((BYTE*)this) - sizeof(void*);
    long cRef = InterlockedDecrement(&(((CDialogEventHandler*)this)->_cRef));
    if (!cRef) free(this);
    return cRef;
}
//implementation of the remaining functions
...
//Creation of the object
static const IFileDialogEventsVtbl vtbl1 =
{
    //IUnknown
    .AddRef = AddRef_IFileDialogEvents,
    .QueryInterface = QueryInterface_IFileDialogEvents,
    .Release = Release_IFileDialogEvents,

    //IFileDialogEvents
    .OnFileOk = _OnFileOk,
    .OnFolderChange = _OnFolderChange,
    .OnFolderChanging = _OnFolderChanging,
    .OnSelectionChange = _OnSelectionChange,
    .OnShareViolation = _OnShareViolation,
    .OnTypeChange = _OnTypeChange,
    .OnOverwrite = _OnOverwrite,
};
static const IFileDialogControlEventsVtbl vtbl2 =
{
    //IUnknown
    .AddRef = AddRef_IFileDialogControlEvents,
    .QueryInterface = QueryInterface_IFileDialogControlEvents,
    .Release = Release_IFileDialogControlEvents,

    //IFileDialogControlEvents
    .OnItemSelected = _OnItemSelected,
    .OnControlActivating = _OnControlActivating,
    .OnButtonClicked = _OnButtonClicked,
    .OnCheckButtonToggled = _OnCheckButtonToggled,
};

CDialogEventHandler* InitCDialogEventHandler()
{
    CDialogEventHandler* h = malloc(sizeof(CDialogEventHandler));
    if (!h) return NULL;
    h->lpVtbl1 = &vtbl1;
    h->lpVtbl2 = &vtbl2;
    h->_cRef = 1;
    return h;
}
    

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM