/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Written by Dan Ogles

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __COMDEFS_H__
#define __COMDEFS_H__

typedef int COMBOOL;

#ifdef NO_COM_SUPPORT

#define EXTERN_C extern "C"

#define interface struct

typedef long HRESULT;

#define MAKE_HRESULT(sev,fac,code) \
  ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )

#if defined (OS_WIN32)
#  define STDMETHODCALLTYPE       __stdcall
#  define STDMETHODVCALLTYPE      __cdecl
#  define STDAPICALLTYPE          __stdcall
#  define STDAPIVCALLTYPE         __cdecl
typedef int (WINAPI *PROC) ();
#else
#  define STDMETHODCALLTYPE
#  define STDMETHODVCALLTYPE
#  define STDAPICALLTYPE
#  define STDAPIVCALLTYPE
typedef int (*PROC) ();
#endif

// exports the following symbol for STDAPI, STDAPIV
#if defined(OS_BE)
#define EXPSYMB __declspec(dllexport)
#else
#define EXPSYMB
#endif // OS_BE

#define STDMETHOD(method)       virtual HRESULT STDMETHODCALLTYPE method
#define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method
#define PURE                    = 0

#define STDAPI                  EXTERN_C EXPSYMB HRESULT STDAPICALLTYPE
#define STDAPI_(type)           EXTERN_C EXPSYMB type STDAPICALLTYPE

#define STDMETHODIMP            HRESULT STDMETHODCALLTYPE
#define STDMETHODIMP_(type)     type STDMETHODCALLTYPE

// The 'V' versions allow Variable Argument lists.

#define STDAPIV                 EXTERN_C EXPSYMB HRESULT STDAPIVCALLTYPE
#define STDAPIV_(type)          EXTERN_C EXPSYMB type STDAPIVCALLTYPE

#define STDMETHODIMPV           HRESULT STDMETHODVCALLTYPE
#define STDMETHODIMPV_(type)    type STDMETHODVCALLTYPE

// Standard OLE typedefs

#ifndef CONST
#define CONST               const
#endif

// Use normal types instead of commented out, if possible
// Most these types conflicts with those defined in os2.h :-(((
typedef unsigned long       DWORD;
#ifdef OS_AMIGAOS
#include <exec/types.h>
#endif

typedef void* HINSTANCE;

struct GUID
{
  unsigned long Data1;
  unsigned short Data2;
  unsigned short Data3;
  unsigned char Data4[8];
};

#ifndef INITGUID
# define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  EXTERN_C const GUID name
#else
# 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 } }
#endif // INITGUID

typedef wchar_t WCHAR;
typedef WCHAR TCHAR;

typedef GUID* LPGUID;

typedef GUID IID;
typedef IID* LPIID;

typedef GUID   CLSID;
typedef CLSID* LPCLSID;

typedef const GUID&  REFGUID;
typedef const IID&   REFIID;
typedef const CLSID& REFCLSID;

#ifndef __IUnknown_INTERFACE_DEFINED__
#define __IUnknown_INTERFACE_DEFINED__

extern IID IID_IUnknown;

interface IUnknown
{
  STDMETHOD (QueryInterface) (REFIID riid, void** ppvObject) PURE;
  STDMETHOD_ (ULong, AddRef) () PURE;
  STDMETHOD_ (ULong, Release) () PURE;
};

typedef IUnknown* LPUNKNOWN;

#endif // __IUknown_INTERFACE_DEFINED__

#ifndef __IClassFactory_INTERFACE_DEFINED__
#define __IClassFactory_INTERFACE_DEFINED__

extern IID IID_IClassFactory;

interface IClassFactory : public IUnknown
{
  STDMETHOD (CreateInstance) (IUnknown* pUnkOuter, const REFIID riid, void** ppv) PURE;
  STDMETHOD (LockServer) (COMBOOL bLock) PURE;
};

typedef IClassFactory* LPCLASSFACTORY;

#endif  // __IClassFactory_INTERFACE_DEFINED__

// a pointer to a procedure
#ifdef OS_WIN32
#  define WINAPI __stdcall
#else
#  define WINAPI
#endif // OS_WIN32
typedef int (WINAPI *PROC)();

inline bool operator == (const GUID& r1, const GUID& r2)
{ return !memcmp(&r1, &r2, sizeof(GUID)); }

inline bool operator != (const GUID& r1, const GUID& r2)
{ return !(r1==r2); }

typedef struct  _COAUTHIDENTITY
{
  unsigned short *User;
  unsigned long UserLength;
  unsigned short *Domain;
  unsigned long DomainLength;
  unsigned short *Password;
  unsigned long PasswordLength;
  unsigned long Flags;
} COAUTHIDENTITY;

typedef struct  _COAUTHINFO
{
  DWORD dwAuthnSvc;
  DWORD dwAuthzSvc;
  wchar_t* pwszServerPrincName;
  DWORD dwAuthnLevel;
  DWORD dwImpersonationLevel;
  COAUTHIDENTITY *pAuthIdentityData;
  DWORD dwCapabilities;
} COAUTHINFO;

typedef struct  _COSERVERINFO
{
  DWORD dwReserved1;
  wchar_t pwszName;
  COAUTHINFO *pAuthInfo;
  DWORD dwReserved2;
} COSERVERINFO;

// HRESULT Helpers
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT) _sc)

// Severity values
#define SEVERITY_SUCCESS    0
#define SEVERITY_ERROR      1


// Generic test for success on any status value (non-negative numbers
// indicate success).
#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)

// and the inverse
#define FAILED(Status) ((HRESULT)(Status)<0)

// Generic test for error on any status value.
#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)

// Return the code
#define HRESULT_CODE(hr)    ((hr) & 0xFFFF)
#define SCODE_CODE(sc)      ((sc) & 0xFFFF)

//  Return the facility
#define HRESULT_FACILITY(hr)  (((hr) >> 16) & 0x1fff)
#define SCODE_FACILITY(sc)    (((sc) >> 16) & 0x1fff)

//  Return the severity
#define HRESULT_SEVERITY(hr)  (((hr) >> 31) & 0x1)
#define SCODE_SEVERITY(sc)    (((sc) >> 31) & 0x1)

// Standard COM errors.
#define E_UNEXPECTED                     _HRESULT_TYPEDEF_(0x8000FFFFL)
#define REGDB_E_CLASSNOTREG              _HRESULT_TYPEDEF_(0x80040154L)
#define CO_E_DLLNOTFOUND                 _HRESULT_TYPEDEF_(0x800401F8L)
#define CO_E_ERRORINDLL                  _HRESULT_TYPEDEF_(0x800401F9L)
#define E_NOINTERFACE                    _HRESULT_TYPEDEF_(0x80000004L)
#define E_FAIL                           _HRESULT_TYPEDEF_(0x80004005L)
#define CLASS_E_NOAGGREGATION            _HRESULT_TYPEDEF_(0x80040110L)
#define E_OUTOFMEMORY                    _HRESULT_TYPEDEF_(0x8007000EL)
#define E_INVALIDARG                     _HRESULT_TYPEDEF_(0x80070057L)

// Success Results
#define S_OK                                   ((HRESULT)0x00000000L)
#define S_FALSE                                ((HRESULT)0x00000001L)

#ifndef TRUE
#  define TRUE        true
#endif
#ifndef FALSE
#  define FALSE       false
#endif

#else // NO_COM_SUPPORT

#ifdef OS_WIN32
#include <wtypes.h>
#endif

#endif // !NO_COM_SUPPORT

// Crystal Space specific COM helpers.

#ifdef _DEBUG
#  include <assert.h>
#  define ASSERT(expression) assert(expression)
#  define VERIFY_SUCCESS(expression) assert(SUCCEEDED(expression))
#  define VERIFY_RESULT(expression, result) assert(expression == result)
#else
#  define ASSERT(expression)
#  define VERIFY_SUCCESS(expression) expression
#  define VERIFY_RESULT(expression, result) expression
#endif

/// use this to register an in-proc server.
struct DllRegisterData
{
  const CLSID *clsid;
  char *szProgID;
  char *szFriendlyName;
#if defined (CS_STATIC_LINKED)
  IUnknown *pClass;
#else
  char *szInProcServer;
#endif
};

// use this to define our own HRESULT return values.
#define MAKE_CSHRESULT(code) MAKE_HRESULT (1, FACILITY_ITF, code)
#define MAKE_SUCCESS_CSHRESULT(code) MAKE_HRESULT (0, FACILITY_ITF, code)

#define COM_METHOD_DECL virtual HRESULT STDMETHODCALLTYPE

// this macro sets up the pThis pointer.
#define METHOD_PROLOGUE(theClass, localClass) \
  theClass* pThis = ((theClass*)((unsigned char*)this - offsetof(theClass, m_x##localClass)));

// a standard way of directing interface 'get' property calls to internal calls.
#define IMPLEMENT_GET_PROPERTY( external, internal, type, internalclass, extname ) \
STDMETHODIMP I##extname::external( type& retval ) \
{ \
  METHOD_PROLOGUE( internalclass, extname ) \
  retval = pThis->internal; \
  return S_OK; \
}

// use a pointer instead of a reference.
#define IMPLEMENT_GET_PROPERTY_PTR( external, internal, type, internalclass, extname) \
STDMETHODIMP I##extname::external( type* retval ) \
{ \
  METHOD_PROLOGUE( internalclass, extname ) \
  *retval = pThis->internal; \
  return S_OK; \
}

// a standard way of directing interface 'set' property calls to internal calls.
#define IMPLEMENT_SET_PROPERTY( external, internal, type, internalclass, extname ) \
STDMETHODIMP I##extname::external (type newval) \
{ \
  METHOD_PROLOGUE (internalclass, extname) \
  pThis->internal = newval; \
  return S_OK; \
}

// a standard way of redirecting from external functions to internal.
#define IMPLEMENT_METHOD( external, internal, internalclass, extname ) \
STDMETHODIMP I##extname::external () \
{ \
  METHOD_PROLOGUE (internalclass, extname) \
  pThis->internal (); \
  return S_OK; \
}

#define FINAL_RELEASE( d ) if (d!=NULL) { d->Release(); d = NULL; }

typedef unsigned long CS_HLIBRARY;

/// On initialization every dynamically-linked library should call this
STDAPI DllInitialize ();

///
STDAPI csCoCreateInstance (REFCLSID rclsid, IUnknown* pUnkOuter,
  unsigned long dwClsContext, REFIID riid, void** ppv);
///
STDAPI csCoGetClassObject (REFCLSID rclsid, DWORD dwClsContext,
  COSERVERINFO * pServerInfo, REFIID riid, void** ppv);
///
STDAPI csCoInitialize (void* lpReserved);
///
STDAPI_(void) csCoUninitialize ();
///
STDAPI csCLSIDFromProgID (char** lpszProgID, LPCLSID pclsid);
///
STDAPI csProgIDFromCLSID (REFCLSID clsid, char** lpszProgID);
///
STDAPI csRegisterServer (const DllRegisterData* dllRegData);
///
STDAPI csUnregisterServer (const DllRegisterData* dllRegData);
///
extern CS_HLIBRARY csLoadLibrary (char* szLibName);
///
extern PROC csGetProcAddress (CS_HLIBRARY hLib, char* szProcName);
///
extern bool csFreeLibrary (CS_HLIBRARY hLib);
///
extern void csFreeAllLibraries ();
	
#endif // __COMDEFS_H__
