#ifndef _OBJREF_H_
#define _OBJREF_H_

#include <atlbase.h>
#include <atlconv.h>

//------------------------------------------------------------------------

#ifndef __REQUIRED_RPCNDR_H_VERSION__
    #define __REQUIRED_RPCNDR_H_VERSION__ 440
#endif

#include "rpc.h"
#include "rpcndr.h"

#ifndef __RPCNDR_H_VERSION__
    #error this stub requires an updated version of <rpcndr.h>
#endif // __RPCNDR_H_VERSION__

#ifndef COM_NO_WINDOWS_H
    #include "windows.h"
    #include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/

#include "oaidl.h"
#include "ocidl.h"

///// Basic Definitions
#define    RPC_E_INVALID_OXID    ( 0x80010151 )
#define    RPC_E_INVALID_SET    ( 0x80010152 )
#define    MSHLFLAGS_NOPING    ( 4 )
#define    MSHLFLAGS_SIMPLEIPID    ( 8 )
#define    MSHLFLAGS_KEEPALIVE    ( 16 )

typedef unsigned hyper ID;
typedef ID MID;
typedef ID OXID;
typedef ID OID;
typedef ID SETID;
typedef GUID IPID;
typedef GUID CID;
typedef REFGUID REFIPID;

#define    COM_MAJOR_VERSION    ( 5 )
#define    COM_MINOR_VERSION    ( 1 )

//////////////////////////////////////////////////////////////////
// ORPC Call Packet Format
//////////////////////////////////////////////////////////////////


typedef struct tagCOMVERSION
{
unsigned short MajorVersion; // Major version number
unsigned short MinorVersion; // Minor version number

} COMVERSION;

const unsigned long ORPCF_NULL = 0; // no additional info in packet
const unsigned long ORPCF_LOCAL = 1; // call is local to this machine
const unsigned long ORPCF_RESERVED1 = 2; // reserved for local use
const unsigned long ORPCF_RESERVED2 = 4; // reserved for local use
const unsigned long ORPCF_RESERVED3 = 8; // reserved for local use
const unsigned long ORPCF_RESERVED4 = 16; // reserved for local use


// Extension to implicit parameters.

typedef struct tagORPC_EXTENT
{
GUID id; // Extension identifier
unsigned long size; // Extension size
byte data[1]; // [size_is((size+7)&~7)]
} ORPC_EXTENT;

// Array of extensions.
typedef struct tagORPC_EXTENT_ARRAY
{
unsigned long size; // Num extents.
unsigned long reserved; // Must be zero.
ORPC_EXTENT** extent; // [size_is((size+1)&~1), unique]

} ORPC_EXTENT_ARRAY;


// implicit 'this' pointer which is the first [in] parameter on
// every ORPC call.
typedef struct tagORPCTHIS
{
COMVERSION version; // COM version number
unsigned long flags; // ORPCF flags for presence of other data
unsigned long reserved1; // set to zero
CID cid; // causality id of caller
ORPC_EXTENT_ARRAY* extensions; // [unique] extensions
} ORPCTHIS;

// implicit 'that' pointer which is the first [out] parameter on
// every ORPC call.
typedef struct tagORPCTHAT
{
unsigned long flags; // ORPCF flags for presence of other data
ORPC_EXTENT_ARRAY *extensions; // [unique] extensions
} ORPCTHAT;



// Marshaled COM Interface Wire Format

/*typedef enum tagMSHLFLAGS
{
    MSHLFLAGS_NORMAL = 0,
    MSHLFLAGS_TABLESTRONG = 1,
    MSHLFLAGS_TABLEWEAK = 2,
} MSHLFLAGS;*/

// Tower IDs for common protocols
#define NCADG_IP_UDP    0x08;
#define NCACN_IP_TCP    0x07;
#define NCADG_IPX 0x0E;
#define NCACN_SPX 0x0C;
#define NCACN_NB_NB 0x12;
#define NCACN_NB_IPX 0x0D;
#define NCACN_DNET_NSP 0x04;
#define NCALRPC 0x10;

// This is the return type for arrays of string bindings or protseqs
// used by many ORPC interfaces.
typedef struct tagSTRINGBINDING
{
unsigned short wTowerId; // Cannot be zero.
unsigned short aNetworkAddr; // Zero terminated.
} STRINGBINDING;

// this value (invalid in DCE RPC) indicates to use default authz
#define COM_C_AUTHZ_NONE 0xffff;

typedef struct tagSECURITYBINDING
{
unsigned short wAuthnSvc; // Must not be zero
unsigned short wAuthzSvc; // Must not be zero
unsigned short aPrincName; // NULL terminated
} SECURITYBINDING;

// DUALSTRINGARRAYS are the return type for arrays of network
// addresses, arrays of endpoints and arrays of both used in
// many ORPC interfaces

typedef struct tagDUALSTRINGARRAY
{

    unsigned short wNumEntries; // # of entries in array
    unsigned short wSecurityOffset; // Offset of security info

// The array contains two parts, a set of STRINGBINDINGs
// and a set of SECURITYBINDINGs. Each set is terminated by an
// extra zero. The shortest array contains four zeros.

    unsigned short aStringArray[1]; // [size_is(wNumEntries)]

} DUALSTRINGARRAY;// arbitrary value to help ensure validity


#define OBJREF_SIGNATURE 0x574f454d
#define OBJREF_STANDARD 0x1
#define OBJREF_HANDLER 0x2
#define OBJREF_CUSTOM 0x4

// Flag values for a STDOBJREF (standard part of an OBJREF).
// SORF_OXRES1 - SORF_OXRES8 are reserved for the object exporters
// use only, object importers must ignore them and must not enforce// MBZ.

#define SORF_NULL = 0x0000; // convenient for init
#define SORF_OXRES1 = 0x0001; // reserved by exporter
#define SORF_OXRES2 = 0x0020; // reserved by exporter
#define SORF_OXRES3 = 0x0040; // reserved by exporter
#define SORF_OXRES4 = 0x0080; // reserved by exporter
#define SORF_OXRES5 = 0x0100; // reserved by exporter
#define SORF_OXRES6 = 0x0200; // reserved by exporter
#define SORF_OXRES7 = 0x0400; // reserved by exporter
#define SORF_OXRES8 = 0x0800; // reserved by exporter
#define SORF_NOPING = 0x1000; // Pinging not required


typedef struct tagSTDOBJREF
{
unsigned long flags; // SORF_ flags (see above)
unsigned long cPublicRefs; // count of references passed
OXID oxid; // oxid of server with this oid
OID oid; // oid of object with this ipid
IPID ipid; // ipid of Interface
} STDOBJREF;

// although this structure is conformant, it is always marshaled
// in little-endian byte-order.

typedef struct tagOBJREF
{
unsigned long signature; // must be OBJREF_SIGNATURE
unsigned long objRefflags; // OBJREF flags (see above)
GUID iid; // interface identifier

union
{ // [switch_is(flags), switch_type(unsigned long)]
struct
    { // [case(OBJREF_STANDARD)]
STDOBJREF std; // standard objref
DUALSTRINGARRAY saResAddr; // resolver address
    } u_standard;
struct
    { // [case(OBJREF_HANDLER)]
STDOBJREF std; // standard objref
CLSID clsid; // Clsid of handler code
DUALSTRINGARRAY saResAddr; // resolver address
    } u_handler;
struct
    { // [case(OBJREF_CUSTOM)]
CLSID clsid; // Clsid of unmarshaling code
unsigned long cbExtension; // size of extension data
unsigned long size; // size of data that follows
byte *pData; // extension + class specific data [size_is(size), ref]
    } u_custom;

} u_objref;

} OBJREF;// wire representation of a marshalled interface pointer,


// always the little-endian form of an OBJREF
typedef struct tagMInterfacePointer
{
ULONG ulCntData; // size of data
byte abData[1]; // [size_is(ulCntData)] data
} MInterfacePointer, *PMInterfacePointer;

// OXID Resolver information associated with each OXID.
typedef struct tagOXID_INFO
{
DWORD dwTid; // thread id of object exporter
DWORD dwPid; // process id of obj exporter
IPID ipidRemUnknown; // IRemUnknown IPID for objectexporter
DWORD dwAuthnHint;
DUALSTRINGARRAY *psa; // protocol and security info
} OXID_INFO;


//-----------------------------------------------------------------------
void DumpGUID(GUID& guid, LPTSTR pszMessage)
{
    TCHAR psz[1024]; //TODO
    LPOLESTR pszGUID = NULL;
    StringFromCLSID(guid, &pszGUID);
   
    USES_CONVERSION;
    lstrcpy(psz,pszMessage);
    lstrcat(psz,"--");
    lstrcat(psz,OLE2T(pszGUID));

     ::CoTaskMemFree(pszGUID);
    OutputDebugString(psz);
}

//-----------------------------------------------------------------------

HRESULT ShowMeMyOBJREF(/*[in]*/IStream* pStm)
{
    if(!pStm)
    {
        return E_POINTER;
    }

    HGLOBAL hg = 0;
    HRESULT hr = ::GetHGlobalFromStream(pStm,&hg);

    OBJREF *pObj = (OBJREF*)GlobalLock(hg);   

    if(!pObj)
    {
        return RPC_E_INVALID_OBJREF;
    }
    //Signature (always MEOW but anyway)
    if(pObj->signature == OBJREF_SIGNATURE)
    {
        ATLTRACE(_T("The signature is MEOW\n"));
    }
   
    //IID
    DumpGUID(pObj->iid,_T("\nThe IID getting marshaled is "));
       
    //Type of OBJREF
    switch(pObj->objRefflags)
    {
        case 1:
        {
            ATLTRACE(_T("\nThe Reference is STANDARD"));
           
            //STDOBJREF Begins

            //SORF flags
            ATLTRACE(_T("\nThe SORF flags for the OBJREF are %d "),pObj->u_objref.u_standard.std.flags);
                   
            //RefCounts
            ATLTRACE(_T("\nThe Reference Counts on the OBJREF is %d "),pObj->u_objref.u_standard.std.cPublicRefs);
           
            //OXID
            _ui64toa(pObj->u_objref.u_standard.std.oxid,psz,10);
            ATLTRACE(_T("\nThe OXID of the STDOBJREF is %s "),psz);

            //OID
            _ui64toa(pObj->u_objref.u_standard.std.oid,psz,10);
            ATLTRACE(_T("\nThe OID of the STDOBJREF is %s"),psz);

            //IPID
            DumpGUID(pObj->u_objref.u_standard.std.ipid,_T("\nIPID of the STDOBJREF"));

            //TODO :Dualstring array
            //DUALSTRINGARRAY da = pObj->u_objref.u_standard.saResAddr;
            break;
        }
        case 2:
        {
            ATLTRACE(_T("\nThe Reference is HANDLER\n"));
           
            //STDOBJREF part of the custom handler

            //SORF flags
            ATLTRACE(_T("\nThe SORF flags for the OBJREF are %d "),pObj->u_objref.u_handler.std.flags);
                       
            //RefCounts
            ATLTRACE(_T("\nThe Reference Counts on the OBJREF is %d "),pObj->u_objref.u_handler.std.cPublicRefs);
           
            //OXID
            _ui64toa(pObj->u_objref.u_handler.std.oxid,psz,10);
            ATLTRACE(_T("\nThe OXID of the STDOBJREF is %s "),psz);
           
            //OID
            _ui64toa(pObj->u_objref.u_handler.std.oid,psz,10);
            ATLTRACE(_T("\nThe OID of the STDOBJREF is %s"),psz);

            //IPID
            DumpGUID(pObj->u_objref.u_handler.std.ipid,_T("\nIPID of the Custom OBJREF"));

            //clsid of the handler
            DumpGUID(pObj->u_objref.u_handler.clsid,_T("\nCLSID of the Custom Handler"));
           
            //TODO :Dualstring array
            //DUALSTRINGARRAY da = pObj->u_objref.u_standard.saResAddr;

            break;
        }
        case 4:
        {
            ATLTRACE(_T("\nThe Reference is CUSTOM"));
           
            //clsid of the handler
            DumpGUID(pObj->u_objref.u_custom.clsid,_T("\nCLSID of the Custom Proxy"));
            break;
        }
        default:
        {
            ATLTRACE(_T("\nThe Reference is of Unknown type"));
            break;
        }
    }

    GlobalUnlock(hg);   
    return hr;
}

#endif //_OBJREF_H_