mstorsjo / llvm-mingw

An LLVM/Clang/LLD based mingw-w64 toolchain
Other
1.75k stars 176 forks source link

How to use COM interfaces from plain C #433

Open jfgimenez opened 2 weeks ago

jfgimenez commented 2 weeks ago

Hi,

I've noticed that COM interfaces are not fully declared in order to be used from plain C, and I'm getting errors in my code. For example, this is the IProgressDialog at shlobj.h:

#define INTERFACE IProgressDialog
  DECLARE_INTERFACE_IID_ (IProgressDialog, IUnknown, "EBBC7C04-315E-11d2-B62F-006097DF5BD4") {
    STDMETHOD(StartProgressDialog) (THIS_ HWND hwndParent, IUnknown *punkEnableModless, DWORD dwFlags, LPCVOID pvResevered) PURE;
    STDMETHOD(StopProgressDialog) (THIS) PURE;
    STDMETHOD(SetTitle) (THIS_ PCWSTR pwzTitle) PURE;
    STDMETHOD(SetAnimation) (THIS_ HINSTANCE hInstAnimation, UINT idAnimation) PURE;
    STDMETHOD_(WINBOOL, HasUserCancelled) (THIS) PURE;
    STDMETHOD(SetProgress) (THIS_ DWORD dwCompleted, DWORD dwTotal) PURE;
    STDMETHOD(SetProgress64) (THIS_ ULONGLONG ullCompleted, ULONGLONG ullTotal) PURE;
    STDMETHOD(SetLine) (THIS_ DWORD dwLineNum, PCWSTR pwzString, WINBOOL fCompactPath, LPCVOID pvResevered) PURE;
    STDMETHOD(SetCancelMsg) (THIS_ PCWSTR pwzCancelMsg, LPCVOID pvResevered) PURE;
    STDMETHOD(Timer) (THIS_ DWORD dwTimerAction, LPCVOID pvResevered) PURE;
  };

And this is the same interface in my current (rather old) mingw:

#define INTERFACE IProgressDialog
  DECLARE_INTERFACE_IID_ (IProgressDialog, IUnknown, "EBBC7C04-315E-11d2-B62F-006097DF5BD4") {
#ifndef __cplusplus
    STDMETHOD(QueryInterface) (THIS_ REFIID riid,LPVOID *ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS) PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;
#endif
    STDMETHOD(StartProgressDialog) (THIS_ HWND hwndParent, IUnknown *punkEnableModless, DWORD dwFlags, LPCVOID pvResevered) PURE;
    STDMETHOD(StopProgressDialog) (THIS) PURE;
    STDMETHOD(SetTitle) (THIS_ PCWSTR pwzTitle) PURE;
    STDMETHOD(SetAnimation) (THIS_ HINSTANCE hInstAnimation, UINT idAnimation) PURE;
    STDMETHOD_(WINBOOL, HasUserCancelled) (THIS) PURE;
    STDMETHOD(SetProgress) (THIS_ DWORD dwCompleted, DWORD dwTotal) PURE;
    STDMETHOD(SetProgress64) (THIS_ ULONGLONG ullCompleted, ULONGLONG ullTotal) PURE;
    STDMETHOD(SetLine) (THIS_ DWORD dwLineNum, PCWSTR pwzString, WINBOOL fCompactPath, LPCVOID pvResevered) PURE;
    STDMETHOD(SetCancelMsg) (THIS_ PCWSTR pwzCancelMsg, LPCVOID pvResevered) PURE;
    STDMETHOD(Timer) (THIS_ DWORD dwTimerAction, LPCVOID pvResevered) PURE;
  };

As you can see, the methods inherited from IUnknown are not declared now, so I cannot call them. This code:

obj->lpVtbl->Release( obj ); causes: "error: no member named 'Release' in 'struct IProgressDialogVtbl'"

So, the question is: How should I use COM interfaces from plain C? How may I call those inherited methods?

TIA

Biswa96 commented 2 weeks ago

Those COM interface definition matches with Windows SDK. Should those be used in C code?

alvinhochun commented 2 weeks ago

I shall point out I have no experience with using COM from C and I am not all that familiar with COM.

However, looking at it I'm like 80% sure that the COM interface declarations in shlobj.h are simply broken for C, both "recent" versions of mingw-w64 (since https://github.com/mingw-w64/mingw-w64/commit/945475c210f169293d829bfcf38a1ef7520a8fa4) and Windows SDK ones. It seems to me the mingw-w64 one got broken from trying to match the Windows SDK definitions. I'd also guess that the Windows 7 SDK might be the last version to have the correct declarations.

It is a bit surprising that these declarations have been broken for more than 10 years and nobody has reported to either Microsoft or mingw-w64, but it also kind of make sense that it is probably quite rare for developers to use pure C for COM. However, with a cursory search I did find someone else documenting this issue in 2015: https://github.com/andlabs/winiconview/blob/master/progressdialog.c

The proper way going forward is to first get Microsoft to fix their SDK headers. Perhaps https://developercommunity.microsoft.com/cpp is the place to report the issue? (There had been precedence of MS fixing headers for C, e.g. this issue with return value, so they might actually fix this one too if they are made aware about it.)

Since mingw-w64 tries to be somewhat compatible with them, it may not make sense for mingw-w64 to implement a workaround on its own. However, this discussion should happen on the mingw-w64-public mailing list.

jfgimenez commented 2 weeks ago

Hi,

thanks for replying. I was using mingw dated 2018. I can't find now the webpage from where I downloaded it, but these are the first lines from build-info.txt:

# **************************************************************************
version : MinGW-W64-builds-4.3.4
user    : niXman
date    : 03.20.2018- 1:18:21 PM
args    : --mode=gcc-7.3.0 --buildroot=/c/mingw730 --rt-version=v5 --jobs=4 --rev=0 --bootstrap --threads=win32 --exceptions=sjlj --arch=i686 --bin-compress
PATH    : /usr/local/bin:/usr/bin:/bin:/opt/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
CFLAGS  : -O2 -pipe -fno-ident
CXXFLAGS: -O2 -pipe -fno-ident
CPPFLAGS: 
LDFLAGS : -pipe -fno-ident
# **************************************************************************

I don't know when become unusable, but for sure it was working fine in that version.

BTW, I was using mingw in 32 bit mode. But now, I'm moving my code to 64 bit, so I decided to use this distro just because it supports 32 and 64 bit from one unique package, and I need to support also 32 bits yet. I'm aware that the underlying compiler is llvm-clang instead of gcc, but I expect no big problem about it.

I'll try to workaround this problem and go on. Even if I have to modify some header files from mingw :-(

Thanks again!

starg2 commented 2 weeks ago

I can't find now the webpage from where I downloaded it

I think it's here:

https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/7.3.0/threads-win32/sjlj/


FYI, the mingw-builds project has moved to GitHub. The build scripts are published here as well.