#ifndef __COM_H #define __COM_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #ifndef callconv_defined #ifdef _MSC_VER #define STDCALL __stdcall #define CDECL __cdecl #else #define STDCALL __attribute__((stdcall)) #define CDECL __attribute__((cdecl)) #endif #define callconv_defined #endif typedef unsigned long ULONG; #define S_OK 0 #define S_FALSE 1 #define E_FAIL 0x80000000 #define SUCCEEDED(hr) (((hr) & 0x80000000) == 0) #define FAILED(hr) (((hr) & 0x80000000) == 0x80000000) #ifndef GUID_DEFINED #define GUID_DEFINED typedef struct GUID GUID, IID, CLSID; struct GUID { dword Data1; word Data2; word Data3; byte Data4[8]; }; #endif #ifdef __cplusplus typedef const IID& REFIID; #else typedef const IID* REFIID; #endif #ifdef __cplusplus #define DECLARE_INTERFACE(name) struct name #define STDMETHOD(name) virtual HRESULT STDCALL name #define STDMETHOD_(type, name) virtual type STDCALL name #define PURE = 0 #define THIS #define THIS_ #define EXTERN_C extern "C" #define InlineIsEqualGUID(rguid1, rguid2) \ (((long*) &rguid1)[0] == ((long*) &rguid2)[0] && \ ((long*) &rguid1)[1] == ((long*) &rguid2)[1] && \ ((long*) &rguid1)[2] == ((long*) &rguid2)[2] && \ ((long*) &rguid1)[3] == ((long*) &rguid2)[3]) /* end C++ declaration */ #else #define DECLARE_INTERFACE(name) \ typedef struct name name; \ struct name { const struct name##Vtbl* vtbl; }; \ struct name##Vtbl \ #define STDMETHOD(name) HRESULT (STDCALL *name) #define STDMETHOD_(type, name) type (STDCALL *name) #define PURE #define THIS_ INTERFACE* this, #define THIS INTERFACE* this #define EXTERN_C #define InlineIsEqualGUID(rguid1, rguid2) \ (((long*) rguid1)[0] == ((long*) rguid2)[0] && \ ((long*) rguid1)[1] == ((long*) rguid2)[1] && \ ((long*) rguid1)[2] == ((long*) rguid2)[2] && \ ((long*) rguid1)[3] == ((long*) rguid2)[3]) /* end C declarations */ #endif #ifdef INITGUID #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ EXTERN_C const GUID name \ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } #else #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ EXTERN_C extern const GUID name #endif #define INTERFACE IUnknown //! Implements standard behaviours for a COM object. /*! * All COM interfaces inherit from IUnknown: they share the three IUnknown * methods as the first three entries in their virtual method table. * Therefore every interface can increment/decrement the object's * reference count (AddRef()/Release()), and it is possible to access * any interface from any other interface (QueryInterface()). * \implement Whenever you are writing an object which implements a COM * interface. * \use Whenever you use a COM interface. */ DECLARE_INTERFACE(IUnknown) { //! Queries the object for a pointer to the specified interface. /*! * As part of the COM standard, every interface to an object should be * able to access every other interface. Therefore the * QueryInterface() function is present in every interface supported * by the object. * * The new interface should be independent of the old one, and must be * Release()'d once it it no longer needed. * * \param iid Specifies the interface to be accessed * \param ppvObject Points to a variable which will receive a pointer * to the new interface. * \return S_OK if the interface was found correctly, or a failure code. */ STDMETHOD(QueryInterface)(THIS_ REFIID iid, void ** ppvObject) PURE; //! Increments the reference count of the object. /*! * Every COM object maintains an internal reference count to allow * for automatic memory management. This reference count should be * incremented when a copy of an interface is made, and * decremented when that interface is no longer needed. When the * reference count reaches zero the object itself destroys itself. * \return Returns the new reference count on the object. This may not be * accurate and should only be used for debugging purposes. */ STDMETHOD_(ULONG, AddRef)(THIS) PURE; //! Decrements the reference count of the object. /*! * The interface should be treated as no longer valid once Release() has * been called on it, since the object may have been destroyed. * \return Returns the new reference count on the object. This may not be * accurate and should only be used for debugging purposes. */ STDMETHOD_(ULONG, Release)(THIS) PURE; }; DEFINE_GUID(IID_IUnknown, 0, 0, 0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); HRESULT IUnknown_QueryInterface(void* ptr, REFIID iid, void** obj); ULONG IUnknown_AddRef(void* ptr); ULONG IUnknown_Release(void* ptr); #ifdef __cplusplus #if 0 extern "C" int wprintf(const wchar_t*, ...); #define IMPLEMENT_IUNKNOWN(cls) \ public: \ dword m_refs; \ \ STDMETHOD_(ULONG, AddRef)() \ { \ wprintf(L"[" L#cls L"::AddRef %d] ", m_refs); \ return ++m_refs; \ } \ \ STDMETHOD_(ULONG, Release)() \ { \ wprintf(L"[" L#cls L"::Release %u] ", m_refs - 1); \ if (m_refs == 0) \ { \ wprintf(L"[delete " L#cls L"] "); \ delete this; \ return 0; \ } \ else \ return m_refs--; \ } #else #define IMPLEMENT_IUNKNOWN(cls) \ public: \ dword m_refs; \ \ STDMETHOD_(ULONG, AddRef)() \ { \ return ++m_refs; \ } \ \ STDMETHOD_(ULONG, Release)() \ { \ if (m_refs == 0) \ { \ delete this; \ return 0; \ } \ else \ return m_refs--; \ } #endif #endif #ifdef __cplusplus } #endif #endif