Почему MinGW-w64 жалуется, что IID_IUnknown и другие не являются указателями в вызовах IsEqualIID() и LresultFromObject()?

Я хочу добавить специальные возможности к своему пользовательскому элементу управления Windows, и, поскольку мне все еще нужно поддерживать все версии Windows XP, я должен использовать MSAA. (Я понимаю, что некоторые люди будут думать, что именно мы должны отталкивать людей от XP, создавая несовместимое программное обеспечение. Лично я этого не понимаю, но это не относится к делу). Этот элемент управления написан на C, поэтому я использую CINTERFACE.

Я написал необходимые заглушки и просто хочу убедиться, что он компилируется нормально. Однако мои вызовы IsEqualIID() и LresultFromObject() жалуются, что IID_IUnknown, IID_IDispatch и IID_IAccessible не являются допустимыми REFIID, а просто обычными GUID без указателя:

In file included from /usr/share/mingw-w64/include/winnt.h:602:0,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
accessibility.h: In function ‘tableAccQueryInterface’:
accessibility.h:13:6: error: incompatible type for argument 2 of ‘memcmp’
  if (IsEqualIID(riid, IID_IUnknown) ||
      ^
In file included from /usr/share/mingw-w64/include/guiddef.h:148:0,
                 from /usr/share/mingw-w64/include/winnt.h:602,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
/usr/share/mingw-w64/include/string.h:40:15: note: expected ‘const void *’ but argument is of type ‘GUID’
   int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
               ^
In file included from /usr/share/mingw-w64/include/winnt.h:602:0,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
accessibility.h:14:3: error: incompatible type for argument 2 of ‘memcmp’
   IsEqualIID(riid, IID_IDispatch) ||
   ^
In file included from /usr/share/mingw-w64/include/guiddef.h:148:0,
                 from /usr/share/mingw-w64/include/winnt.h:602,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
/usr/share/mingw-w64/include/string.h:40:15: note: expected ‘const void *’ but argument is of type ‘GUID’
   int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
               ^
In file included from /usr/share/mingw-w64/include/winnt.h:602:0,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
accessibility.h:15:3: error: incompatible type for argument 2 of ‘memcmp’
   IsEqualIID(riid, IID_IAccessible)) {
   ^
In file included from /usr/share/mingw-w64/include/guiddef.h:148:0,
                 from /usr/share/mingw-w64/include/winnt.h:602,
                 from /usr/share/mingw-w64/include/minwindef.h:146,
                 from /usr/share/mingw-w64/include/windef.h:8,
                 from /usr/share/mingw-w64/include/windows.h:69,
                 from main.c:13:
/usr/share/mingw-w64/include/string.h:40:15: note: expected ‘const void *’ but argument is of type ‘GUID’
   int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
               ^

accessibility.h:259:13: error: incompatible type for argument 1 of ‘LresultFromObject’
  *lResult = LresultFromObject(IID_IAccessible, wParam, t->ta);
             ^
In file included from main.c:22:0:
/usr/share/mingw-w64/include/oleacc.h:109:20: note: expected ‘const struct IID * const’ but argument is of type ‘GUID’
   STDAPI_(LRESULT) LresultFromObject(REFIID riid,WPARAM wParam,LPUNKNOWN punk);
                    ^

Я не понимаю, почему. Практически каждый фрагмент кода, который я нашел, просто использует эти переменные IID напрямую; нет & или что-то в этом роде. Поиск в Google также не помогает; на самом деле он показал мне код, который использует &! Это как-то связано с CINTERFACE? Я делаю что-то еще не так?

(Я знаю, что, скорее всего, нарушу здесь кучу правил COM; я просто хочу убедиться, что все компилируется нормально.)

Используя mingw-w64, который поставляется с Ubuntu GNOME 14.10.

Спасибо.

// 24 december 2014

struct tableAcc {
    IAccessibleVtbl vtbl;
    ULONG refcount;
    struct table *t;
};

static HRESULT STDMETHODCALLTYPE tableAccQueryInterface(IAccessible *this, REFIID riid, void **ppvObject)
{
    if (ppvObject == NULL)
        return E_POINTER;
    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_IDispatch) ||
        IsEqualIID(riid, IID_IAccessible)) {
        *ppvObject = (void *) this;
        return S_OK;
    }
    *ppvObject = NULL;
    return E_NOINTERFACE;
}

#define TA ((struct tableAcc *) this)

// TODO use InterlockedIncrement()/InterlockedDecrement() for these?

static ULONG STDMETHODCALLTYPE tableAccAddRef(IAccessible *this)
{
    TA->refcount++;
    return TA->refcount;
}

static ULONG STDMETHODCALLTYPE tableAccRelease(IAccessible *this)
{
    TA->refcount--;
    if (TA->refcount == 0) {
        free(TA);
        return 0;
    }
    return TA->refcount;
}

// disregard IDispatch: http://msdn.microsoft.com/en-us/library/windows/desktop/cc307844.aspx
// TODO DISP_E_MEMBERNOTFOUND? http://blogs.msdn.com/b/saraford/archive/2004/08/20/which-controls-support-which-msaa-properties-and-how-these-controls-implement-msaa-properties.aspx

static HRESULT STDMETHODCALLTYPE tableAccGetTypeInfoCount(IAccessible *this, UINT *pctinfo)
{
    if (pctinfo == NULL)
        return E_INVALIDARG;
    // TODO assign something to *pctinfo?
    return E_NOTIMPL;
}

static HRESULT STDMETHODCALLTYPE tableAccGetTypeInfo(IAccessible *this, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
    if (ppTInfo == NULL)
        return E_INVALIDARG;
    *ppTInfo = NULL;
    return E_NOTIMPL;
}

static HRESULT STDMETHODCALLTYPE tableAccGetIDsOfNames(IAccessible *this, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
    // TODO verify this one
    if (rgDispId == NULL)
        return E_INVALIDARG;
    // TODO overwrite rgDispId?
    return E_NOTIMPL;
}

static HRESULT STDMETHODCALLTYPE tableAccInvoke(IAccessible *this, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    // TODO check this one
    return E_NOTIMPL;
}

// IAccessible

static HRESULT STDMETHODCALLTYPE tableAccget_accParent(IAccessible *this, IDispatch **ppdispParent)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accChildCount(IAccessible *this, long *pcountChildren)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accChild(IAccessible *this, VARIANT varChild, IDispatch **ppdispChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accName(IAccessible *this, VARIANT varChild, BSTR *pszName)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accValue(IAccessible *this, VARIANT varChild, BSTR *pszValue)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accDescription(IAccessible *this, VARIANT varChild, BSTR *pszDescription)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accRole(IAccessible *this, VARIANT varChild, VARIANT *pvarRole)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accState(IAccessible *this, VARIANT varChild, VARIANT *pvarState)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accHelp(IAccessible *this, VARIANT varChild, BSTR *pszHelp)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accHelpTopic(IAccessible *this, BSTR *pszHelpFile, VARIANT varChild, long *pidTopic)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accKeyboardShortcut(IAccessible *this, VARIANT varChild, BSTR *pszKeyboardShortcut)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accFocus(IAccessible *this, VARIANT *pvarChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accSelection(IAccessible *this, VARIANT *pvarChildren)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccget_accDefaultAction(IAccessible *this, VARIANT varChild, BSTR *pszDefaultAction)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccaccSelect(IAccessible *this, long flagsSelect, VARIANT varChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccaccLocation(IAccessible *this, long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccaccNavigate(IAccessible *this, long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccaccHitTest(IAccessible *this, long xLeft, long yTop, VARIANT *pvarChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccaccDoDefaultAction(IAccessible *this, VARIANT varChild)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccput_accName(IAccessible *this, VARIANT varChild, BSTR szName)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static HRESULT STDMETHODCALLTYPE tableAccput_accValue(IAccessible *this, VARIANT varChild, BSTR szValue)
{
    // TODO
    return DISP_E_MEMBERNOTFOUND;
}

static const IAccessibleVtbl tableAccVtbl = {
    .QueryInterface = tableAccQueryInterface,
    .AddRef = tableAccAddRef,
    .Release = tableAccRelease,
    .GetTypeInfoCount = tableAccGetTypeInfoCount,
    .GetTypeInfo = tableAccGetTypeInfo,
    .GetIDsOfNames = tableAccGetIDsOfNames,
    .Invoke = tableAccInvoke,
    .get_accParent = tableAccget_accParent,
    .get_accChildCount = tableAccget_accChildCount,
    .get_accChild = tableAccget_accChild,
    .get_accName = tableAccget_accName,
    .get_accValue = tableAccget_accValue,
    .get_accDescription = tableAccget_accDescription,
    .get_accRole = tableAccget_accRole,
    .get_accState = tableAccget_accState,
    .get_accHelp = tableAccget_accHelp,
    .get_accHelpTopic = tableAccget_accHelpTopic,
    .get_accKeyboardShortcut = tableAccget_accKeyboardShortcut,
    .get_accFocus = tableAccget_accFocus,
    .get_accSelection = tableAccget_accSelection,
    .get_accDefaultAction = tableAccget_accDefaultAction,
    .accSelect = tableAccaccSelect,
    .accLocation = tableAccaccLocation,
    .accNavigate = tableAccaccNavigate,
    .accHitTest = tableAccaccHitTest,
    .accDoDefaultAction = tableAccaccDoDefaultAction,
    .put_accName = tableAccput_accName,
    .put_accValue = tableAccput_accValue,
};

static struct tableAcc *newTableAcc(struct table *t)
{
    struct tableAcc *ta;

    ta = (struct tableAcc *) malloc(sizeof (struct tableAcc)); ZeroMemory(ta, sizeof (struct tableAcc));
    ta->vtbl = tableAccVtbl;
    ta->vtbl.AddRef(ta);
    ta->t = t;
    return ta;
}

static void freeTableAcc(struct tableAcc *ta)
{
    ta->t = NULL;
    ta->vtbl.Release(ta);
}

static BOOL accessibilityHandler(struct table *t, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
    if (uMsg != WM_GETOBJECT)
        return FALSE;
    if (wParam != OBJID_CLIENT)
        return FALSE;
    *lResult = LresultFromObject(IID_IAccessible, wParam, t->ta);
    // TODO check *lResult
    return TRUE;
}

Заголовки (включены в другой файл, который включает в себя выше):

// 19 october 2014
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
// get Windows version right; right now Windows XP
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_WINDOWS 0x0501       /* according to Microsoft's winperf.h */
#define _WIN32_IE 0x0600            /* according to Microsoft's sdkddkver.h */
#define NTDDI_VERSION 0x05010000    /* according to Microsoft's sdkddkver.h */
#include <windows.h>
#include <commctrl.h>
#include <stdint.h>
#include <uxtheme.h>
#include <string.h>
#include <wchar.h>
#include <windowsx.h>
#include <vsstyle.h>
#include <vssym32.h>
#include <oleacc.h>

person andlabs    schedule 25.12.2014    source источник
comment
Потому что они не указатели. Они являются структурами. При использовании REFIID из C вам нужен оператор & для передачи адреса.   -  person Raymond Chen    schedule 25.12.2014
comment
Спасибо. Итак, я так понимаю, что другой код судится с некоторыми перегрузками, связанными с C++, которые я пропускаю при чтении файлов заголовков? Или я просто воображаю вещи? (Сейчас я просматриваю пример msaa в SDK платформы Windows 7, и он не использует & для LresultFromObject()).   -  person andlabs    schedule 25.12.2014
comment
Ссылки — неотъемлемая часть C++, они не являются перегрузкой, но в C нет этой концепции, поэтому вместо этого вы должны использовать указатели. См. cplusplus.com/articles/ENywvCM9 для обсуждения различий между указателями и ссылками.   -  person Jonathan Potter    schedule 25.12.2014
comment
Этот ответ объясняет. Краткий ответ: определение REFIID меняется в зависимости от того, компилируете ли вы для C или C++.   -  person Raymond Chen    schedule 25.12.2014
comment
@RaymondChen, ну, я дурак, который полностью пропустил этот момент; Благодарность! (И я даже не знал, что вы можете указывать ссылки!)   -  person andlabs    schedule 25.12.2014
comment
@JonathanPotter Я знаю о ссылках на C++; Я думал, что на самом деле это была перегрузка функции со стороны LresultFromObject() (именно это я имел в виду под перегрузкой), а не определение типа REFIID.   -  person andlabs    schedule 25.12.2014