// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFX_OLE_SEG
#pragma code_seg(AFX_OLE_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// Debug helpers

#ifdef _DEBUG
// Helper for converting IID into useful string.  Only for debugging.
LPCTSTR AFXAPI AfxGetIIDString(REFIID iid)
{
	static TCHAR szUnfamiliar[80];
	TCHAR szByte[3];

	struct IID_ENTRY
	{
		const IID* piid;
		LPCTSTR lpszName;
	};

#define MAKE_IID_ENTRY(name) { &name, _T(#name) }

	static const IID_ENTRY iidNameTable[] =
	{
		MAKE_IID_ENTRY(IID_IAdviseSink),
		MAKE_IID_ENTRY(IID_IAdviseSink2),
		MAKE_IID_ENTRY(IID_IBindCtx),
		MAKE_IID_ENTRY(IID_IClassFactory),
		MAKE_IID_ENTRY(IID_IContinueCallback),
		MAKE_IID_ENTRY(IID_IEnumOleDocumentViews),
		MAKE_IID_ENTRY(IID_IOleCommandTarget),
		MAKE_IID_ENTRY(IID_IOleDocument),
		MAKE_IID_ENTRY(IID_IOleDocumentSite),
		MAKE_IID_ENTRY(IID_IOleDocumentView),
		MAKE_IID_ENTRY(IID_IPrint),
		MAKE_IID_ENTRY(IID_IDataAdviseHolder),
		MAKE_IID_ENTRY(IID_IDataObject),
		MAKE_IID_ENTRY(IID_IDebug),
		MAKE_IID_ENTRY(IID_IDebugStream),
		MAKE_IID_ENTRY(IID_IDfReserved1),
		MAKE_IID_ENTRY(IID_IDfReserved2),
		MAKE_IID_ENTRY(IID_IDfReserved3),
		MAKE_IID_ENTRY(IID_IDispatch),
		MAKE_IID_ENTRY(IID_IDropSource),
		MAKE_IID_ENTRY(IID_IDropTarget),
		MAKE_IID_ENTRY(IID_IEnumCallback),
		MAKE_IID_ENTRY(IID_IEnumFORMATETC),
		MAKE_IID_ENTRY(IID_IEnumGeneric),
		MAKE_IID_ENTRY(IID_IEnumHolder),
		MAKE_IID_ENTRY(IID_IEnumMoniker),
		MAKE_IID_ENTRY(IID_IEnumOLEVERB),
		MAKE_IID_ENTRY(IID_IEnumSTATDATA),
		MAKE_IID_ENTRY(IID_IEnumSTATSTG),
		MAKE_IID_ENTRY(IID_IEnumString),
		MAKE_IID_ENTRY(IID_IEnumUnknown),
		MAKE_IID_ENTRY(IID_IEnumVARIANT),
//      MAKE_IID_ENTRY(IID_IExternalConnection),
		MAKE_IID_ENTRY(IID_IInternalMoniker),
		MAKE_IID_ENTRY(IID_ILockBytes),
		MAKE_IID_ENTRY(IID_IMalloc),
		MAKE_IID_ENTRY(IID_IMarshal),
		MAKE_IID_ENTRY(IID_IMessageFilter),
		MAKE_IID_ENTRY(IID_IMoniker),
		MAKE_IID_ENTRY(IID_IOleAdviseHolder),
		MAKE_IID_ENTRY(IID_IOleCache),
		MAKE_IID_ENTRY(IID_IOleCache2),
		MAKE_IID_ENTRY(IID_IOleCacheControl),
		MAKE_IID_ENTRY(IID_IOleClientSite),
		MAKE_IID_ENTRY(IID_IOleContainer),
		MAKE_IID_ENTRY(IID_IOleInPlaceActiveObject),
		MAKE_IID_ENTRY(IID_IOleInPlaceFrame),
		MAKE_IID_ENTRY(IID_IOleInPlaceObject),
		MAKE_IID_ENTRY(IID_IOleInPlaceSite),
		MAKE_IID_ENTRY(IID_IOleInPlaceUIWindow),
		MAKE_IID_ENTRY(IID_IOleItemContainer),
		MAKE_IID_ENTRY(IID_IOleLink),
		MAKE_IID_ENTRY(IID_IOleManager),
		MAKE_IID_ENTRY(IID_IOleObject),
		MAKE_IID_ENTRY(IID_IOlePresObj),
		MAKE_IID_ENTRY(IID_IOleWindow),
		MAKE_IID_ENTRY(IID_IPSFactory),
		MAKE_IID_ENTRY(IID_IParseDisplayName),
		MAKE_IID_ENTRY(IID_IPersist),
		MAKE_IID_ENTRY(IID_IPersistFile),
		MAKE_IID_ENTRY(IID_IPersistStorage),
		MAKE_IID_ENTRY(IID_IPersistStream),
		MAKE_IID_ENTRY(IID_IProxyManager),
		MAKE_IID_ENTRY(IID_IRootStorage),
		MAKE_IID_ENTRY(IID_IRpcChannel),
		MAKE_IID_ENTRY(IID_IRpcProxy),
		MAKE_IID_ENTRY(IID_IRpcStub),
		MAKE_IID_ENTRY(IID_IRunnableObject),
		MAKE_IID_ENTRY(IID_IRunningObjectTable),
		MAKE_IID_ENTRY(IID_IStdMarshalInfo),
		MAKE_IID_ENTRY(IID_IStorage),
		MAKE_IID_ENTRY(IID_IStream),
		MAKE_IID_ENTRY(IID_IStubManager),
		MAKE_IID_ENTRY(IID_IUnknown),
		MAKE_IID_ENTRY(IID_IViewObject),
		MAKE_IID_ENTRY(IID_IViewObject2),
		MAKE_IID_ENTRY(IID_NULL),
	};
#undef MAKE_IID_ENTRY

	// look for it in the table
	for (int i = 0; i < _countof(iidNameTable); i++)
	{
		if (iid == *iidNameTable[i].piid)
			return iidNameTable[i].lpszName;
	}
	// if we get here, it is some IID_ we haven't heard of...

	wsprintf(szUnfamiliar, _T("%8.8X-%4.4X-%4.4X-"),
		iid.Data1, iid.Data2, iid.Data3);
	for (int nIndex = 0; nIndex < 8; nIndex++)
	{
		wsprintf(szByte, _T("%2.2X"), iid.Data4[nIndex]);
		lstrcat(szUnfamiliar, szByte);
	}

	return szUnfamiliar;
}
#endif

/////////////////////////////////////////////////////////////////////////////
// Component object model helpers

/////////////////////////////////////////////////////////////////////////////
// IUnknown client helpers

LPUNKNOWN AFXAPI _AfxQueryInterface(LPUNKNOWN lpUnknown, REFIID iid)
{
	ASSERT(lpUnknown != NULL);

	LPUNKNOWN lpW = NULL;
	if (lpUnknown->QueryInterface(iid, (LPLP)&lpW) != S_OK)
		return NULL;

	return lpW;
}

DWORD AFXAPI _AfxRelease(LPUNKNOWN* lplpUnknown)
{
	ASSERT(lplpUnknown != NULL);
	if (*lplpUnknown != NULL)
	{
		DWORD dwRef = (*lplpUnknown)->Release();
		*lplpUnknown = NULL;
		return dwRef;
	}
	return 0;
}

#define GetInterfacePtr(pTarget, pEntry) \
	((LPUNKNOWN)((BYTE*)pTarget + pEntry->nOffset))

#define GetAggregatePtr(pTarget, pEntry) \
	(*(LPUNKNOWN*)((BYTE*)pTarget + pEntry->nOffset))

/////////////////////////////////////////////////////////////////////////////
// CCmdTarget interface map implementation

// support for aggregation
class CInnerUnknown : public IUnknown
{
public:
	STDMETHOD_(ULONG, AddRef)();
	STDMETHOD_(ULONG, Release)();
	STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj);
};

// calling this function enables an object to be aggregatable
void CCmdTarget::EnableAggregation()
{
	// construct an CInnerUnknown just to get to the vtable
	CInnerUnknown innerUnknown;

	// copy the vtable & make sure initialized
	ASSERT(sizeof(m_xInnerUnknown) == sizeof(CInnerUnknown));
	m_xInnerUnknown = *(DWORD*)&innerUnknown;
}

DWORD CCmdTarget::ExternalAddRef()
{
	// delegate to controlling unknown if aggregated
	if (m_pOuterUnknown != NULL)
		return m_pOuterUnknown->AddRef();

	return InternalAddRef();
}

DWORD CCmdTarget::InternalRelease()
{
	ASSERT(GetInterfaceMap() != NULL);

	if (m_dwRef == 0)
		return 0;

	LONG lResult = InterlockedDecrement(&m_dwRef);
	if (lResult == 0)
	{
		AFX_MANAGE_STATE(m_pModuleState);
		OnFinalRelease();
	}
	return lResult;
}

DWORD CCmdTarget::ExternalRelease()
{
	// delegate to controlling unknown if aggregated
	if (m_pOuterUnknown != NULL)
		return m_pOuterUnknown->Release();

	return InternalRelease();
}

// special QueryInterface used in implementation (does not AddRef)
LPUNKNOWN CCmdTarget::GetInterface(const void* iid)
{
	// allow general hook first chance
	LPUNKNOWN lpUnk;
	if ((lpUnk = GetInterfaceHook(iid)) != NULL)
		return lpUnk;

	const AFX_INTERFACEMAP* pMap = GetInterfaceMap();
	ASSERT(pMap != NULL);
	DWORD lData1 = ((IID*)iid)->Data1;

	// IUnknown is a special case since nobody really implements *only* it!
	BOOL bUnknown = ((DWORD*)&IID_IUnknown)[0] == lData1 &&
		((DWORD*)iid)[1] == ((DWORD*)&IID_IUnknown)[1] &&
		((DWORD*)iid)[2] == ((DWORD*)&IID_IUnknown)[2] &&
		((DWORD*)iid)[3] == ((DWORD*)&IID_IUnknown)[3];
	if (bUnknown)
	{
		do
		{
			const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
			ASSERT(pEntry != NULL);
			while (pEntry->piid != NULL)
			{
				// check INTERFACE_ENTRY macro
				LPUNKNOWN lpUnk = GetInterfacePtr(this, pEntry);

				// check vtable pointer (can be NULL)
				if (*(DWORD*)lpUnk != 0)
					return lpUnk;

				// entry did not match -- keep looking
				++pEntry;
			}
#ifdef _AFXDLL
		} while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
#else
		} while ((pMap = pMap->pBaseMap) != NULL);
#endif

		// interface ID not found, fail the call
		return NULL;
	}

	// otherwise, walk the interface map to find the matching IID
	do
	{
		const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
		ASSERT(pEntry != NULL);
		while (pEntry->piid != NULL)
		{
			if (((DWORD*)pEntry->piid)[0] == lData1 &&
				((DWORD*)pEntry->piid)[1] == ((DWORD*)iid)[1] &&
				((DWORD*)pEntry->piid)[2] == ((DWORD*)iid)[2] &&
				((DWORD*)pEntry->piid)[3] == ((DWORD*)iid)[3])
			{
				// check INTERFACE_ENTRY macro
				LPUNKNOWN lpUnk = GetInterfacePtr(this, pEntry);

				// check vtable pointer (can be NULL)
				if (*(DWORD*)lpUnk != 0)
					return lpUnk;
			}

			// entry did not match -- keep looking
			++pEntry;
		}
#ifdef _AFXDLL
	} while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
#else
	} while ((pMap = pMap->pBaseMap) != NULL);
#endif

	// interface ID not found, fail the call
	return NULL;
}

LPUNKNOWN CCmdTarget::QueryAggregates(const void* iid)
{
	const AFX_INTERFACEMAP* pMap = GetInterfaceMap();
	ASSERT(pMap != NULL);

	// walk the Interface map to call aggregates
	do
	{
		const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
		// skip non-aggregate entries
		ASSERT(pEntry != NULL);
		while (pEntry->piid != NULL)
			++pEntry;

		// call QueryInterface for each aggregate entry
		while (pEntry->nOffset != (size_t)-1)
		{
			LPUNKNOWN lpQuery = GetAggregatePtr(this, pEntry);
			// it is ok to have aggregate but not created yet
			if (lpQuery != NULL)
			{
				LPUNKNOWN lpUnk = NULL;
				if (lpQuery->QueryInterface(*(IID*)iid, (LPLP)&lpUnk)
					== S_OK && lpUnk != NULL)
				{
					// QueryInterface successful...
					return lpUnk;
				}
			}

			// entry did not match -- keep looking
			++pEntry;
		}
#ifdef _AFXDLL
	} while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
#else
	} while ((pMap = pMap->pBaseMap) != NULL);
#endif

	// interface ID not found, fail the call
	return NULL;
}

// real implementation of QueryInterface
DWORD CCmdTarget::InternalQueryInterface(const void* iid, LPVOID* ppvObj)
{
	// check local interfaces
	if ((*ppvObj = GetInterface(iid)) != NULL)
	{
		// interface was found -- add a reference
		ExternalAddRef();
		return S_OK;
	}

	// check aggregates
	if ((*ppvObj = QueryAggregates(iid)) != NULL)
		return S_OK;

	// interface ID not found, fail the call
	return (DWORD)E_NOINTERFACE;
}

// QueryInterface that is exported to normal clients
DWORD CCmdTarget::ExternalQueryInterface(const void* iid,
	LPVOID* ppvObj)
{
	// delegate to controlling unknown if aggregated
	if (m_pOuterUnknown != NULL)
		return m_pOuterUnknown->QueryInterface(*(IID*)iid, ppvObj);

	return InternalQueryInterface(iid, ppvObj);
}

/////////////////////////////////////////////////////////////////////////////
// Inner IUnknown implementation (for aggregation)

STDMETHODIMP_(ULONG) CInnerUnknown::AddRef()
{
	METHOD_PROLOGUE_(CCmdTarget, InnerUnknown)
	return pThis->InternalAddRef();
}

STDMETHODIMP_(ULONG) CInnerUnknown::Release()
{
	METHOD_PROLOGUE(CCmdTarget, InnerUnknown)
	return pThis->InternalRelease();
}

STDMETHODIMP CInnerUnknown::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_(CCmdTarget, InnerUnknown)

	if (iid == IID_IUnknown)
	{
		// QueryInterface on inner IUnknown for IID_IUnknown must
		//  return inner IUnknown.
		pThis->InternalAddRef();
		*ppvObj = this;
		return S_OK;
	}
	return pThis->InternalQueryInterface(&iid, ppvObj);
}

/////////////////////////////////////////////////////////////////////////////
// other helper functions

// ExternalDisconnect is used to remove RPC connections in destructors.  This
//  insures that no RPC calls will go to the object after it has been
//  deleted.
void CCmdTarget::ExternalDisconnect()
{
	if (m_dwRef == 0)   // already in disconnected state?
		return;

	// get IUnknown pointer for the object
	LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
	ASSERT(lpUnknown != NULL);

	// disconnect the object
	InterlockedIncrement(&m_dwRef);  // protect object from destruction
	CoDisconnectObject(lpUnknown, 0);
	m_dwRef = 0;    // now in disconnected state
}

// GetControllingUnknown is used when creating aggregate objects,
//  usually from OnCreateAggregates.  The outer, or controlling, unknown
//  is one of the parameters to CoCreateInstance and other OLE creation
//  functions which support aggregation.
LPUNKNOWN CCmdTarget::GetControllingUnknown()
{
	if (m_pOuterUnknown != NULL)
		return m_pOuterUnknown; // aggregate of m_pOuterUnknown

	LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
	return lpUnknown;   // return our own IUnknown implementation
}

/////////////////////////////////////////////////////////////////////////////
// Inline function declarations expanded out-of-line

#ifndef _AFX_ENABLE_INLINES

// expand inlines for OLE general APIs
static char _szAfxOleInl[] = "afxole.inl";
#undef THIS_FILE
#define THIS_FILE _szAfxOleInl
#define _AFXDISP_INLINE
#include "afxole.inl"

#endif //!_AFX_ENABLE_INLINES

/////////////////////////////////////////////////////////////////////////////
