DirectSound is based on C++ COM object model. This means having public abstract C++ class. And real implementation inherits it and implements all methods.
The way how you use it in C++ are calls to regular C++ methods. In C you don't have methods available in structures/classes. But you access C++ virtual table and call function pointers yourself.
In C++ any COM interface is implemented as abstract class. But in C COM interface is implemented as a struct with one member - lpVtbl pointer. This pointer contains all the methods object implements.
So if you are compiling code as C++ then you can use methods directly, but if you compile code in C (or any other language) you need to access virtual table yourself and call needed function pointer.
To see how it is implemented look in dsound.h and combaseapi.h headers. dsound.h contains declaration of DirectSound interfaces and combaseapi.h contains macros which expands differently depending if you compile code as C or C++.
Look here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | DECLARE_INTERFACE_(IDirectSound, IUnknown)
{
// IUnknown methods
STDMETHOD(QueryInterface) (THIS_ _In_ REFIID, _Outptr_ LPVOID*) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// IDirectSound methods
...
STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE;
...
};
#define IDirectSound_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b)
#define IDirectSound_AddRef(p) IUnknown_AddRef(p)
#define IDirectSound_Release(p) IUnknown_Release(p)
#if !defined(__cplusplus) || defined(CINTERFACE)
...
#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b)
...
#else // !defined(__cplusplus) || defined(CINTERFACE)
...
#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b)
...
#endif // !defined(__cplusplus) || defined(CINTERFACE)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | #if defined(__cplusplus) && !defined(CINTERFACE)
...
#define __STRUCT__ struct
#define interface __STRUCT__
#define STDMETHOD(method) virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE method
...
#define DECLARE_INTERFACE_(iface, baseiface) interface DECLSPEC_NOVTABLE iface : public baseiface
...
#else
#define interface struct
#define STDMETHOD(method) HRESULT (STDMETHODCALLTYPE * method)
#define DECLARE_INTERFACE(iface) typedef interface iface { \
const struct iface##Vtbl FAR* lpVtbl; \
} iface; \
typedef const struct iface##Vtbl iface##Vtbl; \
const struct iface##Vtbl
...
#endif
|
You can see that DECLARE_INTERFACE is either C++ struct with virtual methods or C structure with virtual table pointer to actual function pointers. All wrapped in #ifdef __cplusplus.
You can also see that you can write calls using macros:
| IDirectSound_SetCooperativeLevel(obj, arg1, arg2);
|
Which will expand to correct C or C++ code. That is if you want to switch between C and C++ in your code.