// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 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 AFXCTL_CORE1_SEG
#pragma code_seg(AFXCTL_CORE1_SEG)
#endif

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

#define new DEBUG_NEW

#define _afxTrackingMenu (AfxGetThreadState()->m_hTrackingMenu)

/////////////////////////////////////////////////////////////////////////////
// Special WM_PAINT message handler that includes the HDC

#define ON_WM_PAINT_SPECIAL() \
	{ WM_PAINT, 0, 0, 0, AfxSig_vD, \
		(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(CDC*))&OnPaint },

/////////////////////////////////////////////////////////////////////////////
// Window to serve as "parking space" for not-yet-activated subclassed controls

AFX_MODULE_STATE* AFXAPI _AfxGetOleModuleState();

static HWND PASCAL GetParkingWindow()
{
	_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
	ASSERT(pThreadState != NULL);
	if (pThreadState->m_pWndPark == NULL)
	{
		AFX_MANAGE_STATE(_AfxGetOleModuleState());
		CWnd* pWndTmp;

		TRY
		{
#ifdef _DEBUG
			HWND hWndActive = ::GetActiveWindow();
#endif
			pWndTmp = new CParkingWnd;
			ASSERT(pWndTmp->m_hWnd != NULL);
			ASSERT(hWndActive == ::GetActiveWindow());
		}
		CATCH_ALL(e)
		{
			if (pWndTmp)
				delete pWndTmp;
			pWndTmp = NULL;
		}
		END_CATCH_ALL

		pThreadState->m_pWndPark = pWndTmp;
	}
	return pThreadState->m_pWndPark->GetSafeHwnd();
}

static void PASCAL ReleaseParkingWindow()
{
	_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
	ASSERT(pThreadState != NULL);
	ASSERT(pThreadState->m_nCtrlRef == 0);
	if (pThreadState->m_pWndPark != NULL)
	{
		AFX_MANAGE_STATE(_AfxGetOleModuleState());

		ASSERT(pThreadState->m_pWndPark->m_hWnd != NULL);
		ASSERT(::GetWindow(pThreadState->m_pWndPark->m_hWnd, GW_CHILD) == NULL);
		HWND hWnd = pThreadState->m_pWndPark->Detach();
		::SetWindowLong(hWnd, GWL_WNDPROC, (long)DefWindowProc);
		::DestroyWindow(hWnd);
		delete pThreadState->m_pWndPark;
		pThreadState->m_pWndPark = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////
// COleControl interface map

BEGIN_INTERFACE_MAP(COleControl, CCmdTarget)
	INTERFACE_PART(COleControl, IID_IQuickActivate, QuickActivate)
	INTERFACE_PART(COleControl, IID_IOleObject, OleObject)
	INTERFACE_PART(COleControl, IID_IViewObjectEx, ViewObject)
	INTERFACE_PART(COleControl, IID_IPersistMemory, PersistMemory)
	INTERFACE_PART(COleControl, IID_IPersistStreamInit, PersistStreamInit)
	INTERFACE_PART(COleControl, IID_IProvideClassInfo2, ProvideClassInfo)
	INTERFACE_PART(COleControl, IID_IConnectionPointContainer, ConnPtContainer)
	INTERFACE_PART(COleControl, IID_IOleControl, OleControl)
	INTERFACE_PART(COleControl, IID_IOleInPlaceObject, OleInPlaceObject)
	INTERFACE_PART(COleControl, IID_IOleInPlaceObjectWindowless, OleInPlaceObject)
	INTERFACE_PART(COleControl, IID_IOleInPlaceActiveObject, OleInPlaceActiveObject)
	INTERFACE_PART(COleControl, IID_IDispatch, Dispatch)
	INTERFACE_PART(COleControl, IID_IOleCache, OleCache)
	INTERFACE_PART(COleControl, IID_IViewObject, ViewObject)
	INTERFACE_PART(COleControl, IID_IViewObject2, ViewObject)
	INTERFACE_PART(COleControl, IID_IDataObject, DataObject)
	INTERFACE_PART(COleControl, IID_IPersistPropertyBag, PersistPropertyBag)
	INTERFACE_PART(COleControl, IID_ISpecifyPropertyPages, SpecifyPropertyPages)
	INTERFACE_PART(COleControl, IID_IPerPropertyBrowsing, PerPropertyBrowsing)
	INTERFACE_PART(COleControl, IID_IProvideClassInfo, ProvideClassInfo)
	INTERFACE_PART(COleControl, IID_IPersist, PersistStorage)
	INTERFACE_PART(COleControl, IID_IPersistStorage, PersistStorage)
END_INTERFACE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COleControl event map

const AFX_EVENTMAP COleControl::eventMap = { NULL, NULL };

/////////////////////////////////////////////////////////////////////////////
// COleControl message map

BEGIN_MESSAGE_MAP(COleControl, CWnd)
	ON_WM_PAINT_SPECIAL()
	//{{AFX_MSG_MAP(COleControl)
	ON_WM_NCCREATE()
	ON_WM_NCCALCSIZE()
	ON_WM_SIZE()
	ON_WM_MOVE()
	ON_WM_SHOWWINDOW()
	ON_WM_CREATE()
	ON_MESSAGE(WM_SETTEXT, OnSetText)
	ON_WM_NCPAINT()
	ON_WM_DESTROY()
	ON_WM_ENTERIDLE()
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
	ON_MESSAGE(OCM_CTLCOLORBTN, OnOcmCtlColorBtn)
	ON_MESSAGE(OCM_CTLCOLORDLG, OnOcmCtlColorDlg)
	ON_MESSAGE(OCM_CTLCOLOREDIT, OnOcmCtlColorEdit)
	ON_MESSAGE(OCM_CTLCOLORLISTBOX, OnOcmCtlColorListBox)
	ON_MESSAGE(OCM_CTLCOLORMSGBOX, OnOcmCtlColorMsgBox)
	ON_MESSAGE(OCM_CTLCOLORSCROLLBAR, OnOcmCtlColorScrollBar)
	ON_MESSAGE(OCM_CTLCOLORSTATIC, OnOcmCtlColorStatic)
	ON_WM_MOUSEMOVE()
	ON_WM_NCHITTEST()
	ON_WM_MOUSEACTIVATE()
	ON_WM_NCLBUTTONDOWN()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_MBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_CHAR()
	ON_WM_SYSKEYDOWN()
	ON_WM_SYSKEYUP()
	ON_WM_INITMENUPOPUP()
	ON_WM_MENUSELECT()
	ON_WM_CANCELMODE()
	ON_WM_SETCURSOR()
	ON_WM_GETDLGCODE()
	ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COleControl implementation

COleControl::COleControl() :
	m_font(&m_xFontNotification)
{
	// add to parking window reference count
	_AFX_THREAD_STATE* pState = AfxGetThreadState();
	ASSERT(pState != NULL);
	++pState->m_nCtrlRef;

	m_bFinalReleaseCalled = FALSE;
	m_bChangingExtent = FALSE;
	m_bUIDead = FALSE;

	m_pReflect = NULL;

	m_pClientSite = NULL;
	m_pOleAdviseHolder = NULL;
	m_pDataAdviseHolder = NULL;
	m_pInPlaceSite = NULL;
	m_pInPlaceFrame = NULL;
	m_pInPlaceDoc = NULL;
	m_pControlSite = NULL;

	m_pDefIUnknown = NULL;
	m_pDefIPersistStorage = NULL;
	m_pDefIViewObject = NULL;
	m_pDefIOleCache = NULL;
	m_pAdviseInfo = NULL;

	m_pUIActiveInfo = NULL;
	m_nIDTracking = 0;
	m_nIDLastMessage = 0;
	m_bAutoMenuEnable = TRUE;       // auto enable on by default

	m_bInPlaceActive = FALSE;
	m_bUIActive = FALSE;
	m_bOpen = FALSE;
	m_bPendingUIActivation = FALSE;
	m_pWndOpenFrame = NULL;
	m_bInitialized = FALSE;

	m_dwVersionLoaded = 0;

	m_bModified = TRUE;

	m_iButtonState = 0;
	m_iDblClkState = 0;

	m_sBorderStyle = 0;
	m_sAppearance = 0;
	m_bEnabled = TRUE;
	m_lReadyState = READYSTATE_COMPLETE;

	m_hFontPrev = NULL;

	m_cEventsFrozen = 0;

	m_bConvertVBX = FALSE;

	m_pSimpleFrameSite = NULL;
	m_bSimpleFrame = FALSE;

	m_ptOffset.x = 0;
	m_ptOffset.y = 0;

	m_bNoRedraw = FALSE;

	m_bInPlaceSiteEx = FALSE;
	m_bInPlaceSiteWndless = FALSE;

	m_bOptimizedDraw = FALSE;

	m_bDataPathPropertiesLoaded = TRUE;

	SetInitialSize(100, 50);

	// Wire up aggregation support
	EnableAggregation();

	// Wire up IDispatch support
	EnableAutomation();

	// Wire up connection map support
	EnableConnections();

	m_pDataSource = NULL;

	AfxOleLockApp();
}


COleControl::~COleControl()
{
	if (m_pDataSource != NULL)
		delete m_pDataSource;

	if (m_pReflect != NULL)
		m_pReflect->DestroyWindow();

	if (m_pWndOpenFrame != NULL)
		m_pWndOpenFrame->DestroyWindow();

	RELEASE(m_pClientSite);
	RELEASE(m_pOleAdviseHolder);
	RELEASE(m_pDataAdviseHolder);
	RELEASE(m_pInPlaceSite);
	RELEASE(m_pInPlaceFrame);
	RELEASE(m_pInPlaceDoc);
	RELEASE(m_pControlSite);
	RELEASE(m_pSimpleFrameSite);

	LPUNKNOWN pUnk = GetControllingUnknown();

	InterlockedIncrement(&m_dwRef);  // Keep ref count from going to zero again.

	if (m_pDefIPersistStorage != NULL)
	{
		pUnk->AddRef();
		m_pDefIPersistStorage->Release();
	}

	if (m_pDefIViewObject != NULL)
	{
		pUnk->AddRef();
		m_pDefIViewObject->Release();
	}

	if (m_pDefIOleCache != NULL)
	{
		pUnk->AddRef();
		m_pDefIOleCache->Release();
	}

	if (m_pAdviseInfo != NULL)
	{
		RELEASE(m_pAdviseInfo->m_pAdvSink);
		delete m_pAdviseInfo;
	}

	RELEASE(m_pDefIUnknown);
	InterlockedDecrement(&m_dwRef);

	if (m_hWnd != NULL)
		DestroyWindow();

	// release parking window if reference count is now zero
	_AFX_THREAD_STATE* pState = AfxGetThreadState();
	ASSERT(pState != NULL);
	if (pState->m_nCtrlRef == 0 || --pState->m_nCtrlRef == 0)
		ReleaseParkingWindow();

	AfxOleUnlockApp();
}

void COleControl::OnFinalRelease()
{
	if (!m_bFinalReleaseCalled)
	{
		m_bFinalReleaseCalled = TRUE;

		if (m_hWnd != NULL)
			DestroyWindow();

		CCmdTarget::OnFinalRelease();
	}
}

LPUNKNOWN COleControl::GetInterfaceHook(const void* piid)
{
	ASSERT_POINTER(piid, IID);

	if (m_piidPrimary != NULL && _AfxIsEqualGUID(*m_piidPrimary, *(IID*)piid))
	{
		return GetInterface((void*)&IID_IDispatch);
	}

	if (_AfxIsEqualGUID(IID_IPointerInactive, *(IID*)piid) &&
		(GetControlFlags() & pointerInactive))
	{
		return &m_xPointerInactive;
	}

	return NULL;
}

void COleControl::SetInitialSize(int cx, int cy)
{
	SIZEL szlPixels;
	SIZEL szlHimetric;
	szlPixels.cx = cx;
	szlPixels.cy = cy;
	_AfxXformSizeInPixelsToHimetric(NULL, &szlPixels, &szlHimetric);
	m_cxExtent = szlHimetric.cx;
	m_cyExtent = szlHimetric.cy;
}

BOOL COleControl::GetDispatchIID(IID* pIID)
{
	if (m_piidPrimary != NULL)
		*pIID = *m_piidPrimary;

	return (m_piidPrimary != NULL);
}

void COleControl::InitializeIIDs(const IID* piidPrimary, const IID* piidEvents)
{
	m_piidPrimary = piidPrimary;
	m_piidEvents = piidEvents;

	EnableTypeLib();

	// Initialize the masks for stock events and properties.
	InitStockEventMask();
	InitStockPropMask();

#ifdef _DEBUG

	// Verify that the type library contains all the correct information.
	// If any of the following assertions fail, carefully check the IDs
	// in the control's .CPP file against those in its .ODL file.

	LPTYPEINFO pTypeInfo;
	HRESULT hr;
	CLSID clsid;

	GetClassID(&clsid);
	if (SUCCEEDED(hr = GetTypeInfoOfGuid(0, clsid, &pTypeInfo)))
		RELEASE(pTypeInfo);

	ASSERT(SUCCEEDED(hr));  // Class ID may be corrupted

	if (SUCCEEDED(hr = GetTypeInfoOfGuid(0, *m_piidPrimary, &pTypeInfo)))
		RELEASE(pTypeInfo);

	ASSERT(SUCCEEDED(hr));  // Primary dispatch interface ID may be corrupted

	if (SUCCEEDED(hr = GetTypeInfoOfGuid(0, *m_piidEvents, &pTypeInfo)))
		RELEASE(pTypeInfo);

	ASSERT(SUCCEEDED(hr));  // Event dispatch interface ID may be corrupted

#endif
}

#ifdef _DEBUG

void COleControl::AssertValid() const
{
	CWnd::AssertValid();
}

void AFXAPI _AfxDumpGuid(CDumpContext& dc, const GUID* pGuid)
{
	USES_CONVERSION;

	if (pGuid == NULL)
	{
		dc << "(NULL)";
		return;
	}

	OLECHAR szGuid[40];
	::StringFromGUID2(*pGuid, szGuid, 40);
	dc << OLE2CT(szGuid);
}

void AFXAPI _AfxDumpHex(CDumpContext& dc, DWORD dw)
{
	TCHAR szHex[10];
	wsprintf(szHex, _T("0x%08lx"), dw);
	dc << szHex;
}

void COleControl::Dump(CDumpContext& dc) const
{
	CWnd::Dump(dc);
#ifdef _AFXDLL
	dc << "\nm_pModuleState = " << m_pModuleState;
#endif
	dc << "\nm_piidPrimary = ";
	_AfxDumpGuid(dc, m_piidPrimary);
	dc << "\nm_piidEvents =  ";
	_AfxDumpGuid(dc, m_piidEvents);
	dc << "\nm_dwVersionLoaded = ";
	_AfxDumpHex(dc, m_dwVersionLoaded);
	dc << "\nm_cEventsFrozen = " << m_cEventsFrozen;
	dc << "\nm_rcPos = " << m_rcPos;
	dc << "\nm_cxExtent = " << m_cxExtent;
	dc << "\nm_cyExtent = " << m_cyExtent;
	dc << "\nm_bFinalReleaseCalled = " << m_bFinalReleaseCalled;
	dc << "\nm_bModified = " << m_bModified;
	dc << "\nm_bCountOnAmbients = " << m_bCountOnAmbients;
	dc << "\nm_iButtonState = " << m_iButtonState;
	dc << "\nm_iDblClkState = " << m_iDblClkState;
	dc << "\nm_bInPlaceActive = " << m_bInPlaceActive;
	dc << "\nm_bUIActive = " << m_bUIActive;
	dc << "\nm_bPendingUIActivation = " << m_bPendingUIActivation;
	dc << "\nm_bOpen = " << m_bOpen;
	dc << "\nm_bChangingExtent = " << m_bChangingExtent;
	dc << "\nm_bConvertVBX = " << m_bConvertVBX;
	dc << "\nm_bSimpleFrame = " << m_bSimpleFrame;
	dc << "\nm_bUIDead = " << m_bUIDead;
}

#endif // _DEBUG

/////////////////////////////////////////////////////////////////////////////
// _AfxFillPSOnStack (WINBUG)
//
// Windows has a bug in the WM_PAINT code for the Button control.  If the
// paint is a sub-classed paint, and if the display driver is a Win3.0
// display driver, then Windows calls IsRectEmpty, passing in the rectangle
// from the paint structure.  Since it was a sub-classed paint, and
// BeginPaint was not called, the rectangle struct passed to IsRectEmpty is
// uninitialized.  If IsRectEmpty returned True, then the control was not
// painted.  To work around the bug, we call FillPSOnStack before calling
// windows with the WM_PAINT.  This routine fills a buffer on the stack
// 0x80 bytes of consecutive values from 0 to 0x7f.  That way, if the
// rectangle falls anywhere within this buffer range, and the stack has not
// been modified by other means, then IsRectEmpty will return FALSE, so that
// the control will Paint.

#define WORDBUFSIZE 0x40

void AFXAPI _AfxFillPSOnStack()
{
	// Stack hack needed on Win32s
	WORD buf[WORDBUFSIZE];
	WORD i;
	WORD pat;

	for (i = 0, pat = 0x0100; i < WORDBUFSIZE; i++, pat += 0x0202)
		buf[i] = pat;
}

void COleControl::DoSuperclassPaint(CDC* pDC, const CRect& rcBounds)
{
	if (m_hWnd == NULL)
		CreateWindowForSubclassedControl();

	if (m_hWnd != NULL)
	{
		CRect rcClient;
		GetClientRect(&rcClient);

		if (rcClient.Size() != rcBounds.Size())
		{
			pDC->SetMapMode(MM_ANISOTROPIC);
			pDC->SetWindowExt(rcClient.right, rcClient.bottom);
			pDC->SetViewportExt(rcBounds.Size());
		}
		pDC->SetWindowOrg(0, 0);
		pDC->SetViewportOrg(rcBounds.left, rcBounds.top);

		BOOL bWin4 = afxData.bWin4;
		_AfxFillPSOnStack();
		::CallWindowProc(
				*GetSuperWndProcAddr(),
				m_hWnd, (bWin4 ? WM_PRINT : WM_PAINT),
				(WPARAM)(pDC->m_hDC),
				(LPARAM)(bWin4 ? PRF_CHILDREN | PRF_CLIENT : 0));
	}
}

BOOL COleControl::IsSubclassedControl()
{
	// This default implementation provides some degree of backward
	// compatibility with old controls. New subclassed controls should just
	// override IsSubclassedControl and return TRUE.
	return m_pfnSuper == NULL &&
		GetSuperWndProcAddr() != CWnd::GetSuperWndProcAddr();
}

BOOL COleControl::CreateControlWindow(HWND hWndParent, const CRect& rcPos,
	LPCRECT prcClipped)
{
	if (prcClipped == NULL)
		prcClipped = &rcPos;

	if (m_hWnd == NULL)
	{
		// If window doesn't exist, create it.

		// Test if:
		// we're not subclassing a Windows control, or
		// container reflects messages for us...

		DWORD dwStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
		if (m_sBorderStyle)
			dwStyle |= WS_BORDER;
		if (!m_bEnabled)
			dwStyle |= WS_DISABLED;
		DWORD dwExStyle = WS_EX_NOPARENTNOTIFY;
		if (m_sAppearance)
			dwExStyle |= WS_EX_CLIENTEDGE;

		// we create normally if:
		//       (we're not subclassing -or- the container reflects)
		// -and- the container autoclips for us
		if ((!IsSubclassedControl() || m_bMsgReflect) && m_bAutoClip)
		{
			// Just create the control's window.
			if (AfxDeferRegisterClass(AFX_WNDOLECONTROL_REG))
			{
				CreateEx(dwExStyle, AFX_WNDOLECONTROL, m_strText, dwStyle,
					rcPos.left, rcPos.top, rcPos.Width(), rcPos.Height(),
					hWndParent, 0);
			}
		}
		else    // ...we're subclassing a Windows control.
		{
			if (m_pReflect == NULL)
			{
				// Create a window to reflect notification messages.
				m_pReflect = new CReflectorWnd;
				if (!m_pReflect->Create(prcClipped, hWndParent))
				{
					// If m_pReflect->Create failed, then m_pReflect deleted itself.
					m_pReflect = NULL;
				}
			}
			else
			{
				// Reflector window already exists... just reparent it.
				if (m_pReflect->m_hWnd != NULL)
				{
					::SetParent(m_pReflect->m_hWnd, hWndParent);
					::SetWindowPos(m_pReflect->m_hWnd, NULL, 0, 0, 0, 0,
						SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
						SWP_SHOWWINDOW);
				}
			}

			if (m_pReflect != NULL && m_pReflect->m_hWnd != NULL)
			{
				// Create the control's window.
				CreateEx(dwExStyle, NULL, m_strText, dwStyle,
					m_ptOffset.x, m_ptOffset.y,
					rcPos.Width(), rcPos.Height(),
					m_pReflect->m_hWnd, 0);
				if (m_hWnd == NULL)
				{
					// Window creation failed: cleanup.
					m_pReflect->DestroyWindow();
					m_pReflect = NULL;
				}
			}
		}

		// Set the new window's font.
		OnFontChanged();
	}
	else
	{
		// If window does exist, reparent and reposition it.
		CWnd* pWndOuter = GetOuterWindow();
		ASSERT(pWndOuter != NULL);

		if (::GetParent(pWndOuter->m_hWnd) != hWndParent)
			ReparentControlWindow(pWndOuter->m_hWnd, hWndParent);

		::SetWindowPos(pWndOuter->m_hWnd, NULL, 0, 0, 0, 0,
			SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
			SWP_SHOWWINDOW);

		if (m_pReflect == NULL)
			::MoveWindow(m_hWnd, rcPos.left, rcPos.top,
				rcPos.Width(), rcPos.Height(), TRUE);
		else
		{
			pWndOuter->MoveWindow(prcClipped, TRUE);
			::MoveWindow(m_hWnd, m_ptOffset.x, m_ptOffset.y,
				rcPos.Width(), rcPos.Height(), TRUE);
		}
	}

	ASSERT(m_hWnd != NULL);
	return (m_hWnd != NULL);
}

void COleControl::ReparentControlWindow(HWND hWndOuter, HWND hWndParent)
{
	// can be overridden by subclass, if necessary
	::SetParent(hWndOuter, hWndParent);
}

void COleControl::GetControlSize(int* pcx, int* pcy)
{
	ASSERT_POINTER(pcx, int);
	ASSERT_POINTER(pcy, int);

	SIZEL szlHimetric;
	SIZEL szlPixels;
	szlHimetric.cx = m_cxExtent;
	szlHimetric.cy = m_cyExtent;
	_AfxXformSizeInHimetricToPixels(NULL, &szlHimetric, &szlPixels);
	*pcx = (int)szlPixels.cx;
	*pcy = (int)szlPixels.cy;
}

BOOL COleControl::SetControlSize(int cx, int cy)
{
	SIZEL szlPixels;
	SIZEL szlHimetric;
	szlPixels.cx = cx;
	szlPixels.cy = cy;
	_AfxXformSizeInPixelsToHimetric(NULL, &szlPixels, &szlHimetric);
	return SUCCEEDED(m_xOleObject.SetExtent(DVASPECT_CONTENT, &szlHimetric));
}

void COleControl::ResizeOpenControl(int cx, int cy)
{
	CWnd* pWndOuter = GetOuterWindow();
	if ((pWndOuter != NULL) && (pWndOuter->m_hWnd != NULL))
		::SetWindowPos(pWndOuter->m_hWnd, NULL, 0, 0, cx, cy,
					SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
	ResizeFrameWindow(cx, cy);
}

BOOL COleControl::SetRectInContainer(LPCRECT lpRect)
{
	if ((m_pInPlaceSite != NULL) && m_bInPlaceActive)
	{
		m_pInPlaceSite->OnPosRectChange(lpRect);
		return TRUE;
	}
	else if (m_bOpen)
	{
		ResizeOpenControl(lpRect->right - lpRect->left,
				lpRect->bottom - lpRect->top);
		return TRUE;
	}

	return FALSE;
}

void COleControl::OnResetState()
{
	CResetPropExchange px;
	DoPropExchange(&px);
	InvalidateControl();
}

void AFXAPI _AfxDrawBorders(CDC* pDC, CRect& rc, BOOL bBorder, BOOL bClientEdge)
{
	if (bBorder)
		::DrawEdge(pDC->m_hDC, &rc, (bClientEdge ? BDR_INNER : BDR_OUTER),
			BF_RECT | BF_ADJUST | (bClientEdge ? BF_FLAT : BF_MONO));

	if (bClientEdge)
		::DrawEdge(pDC->m_hDC, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
}

void COleControl::DrawContent(CDC* pDC, CRect& rc)
{
	// Map into device coordinates.

	pDC->LPtoDP(&rc);
	int iSaveDC;
	if (! m_bOptimizedDraw)
		iSaveDC = pDC->SaveDC();
	pDC->SetViewportOrg(0, 0);
	pDC->SetWindowOrg(0, 0);
	pDC->SetMapMode(MM_TEXT);
	m_rcBounds = rc;
	if (pDC->GetDeviceCaps(TECHNOLOGY) == DT_RASDISPLAY)
		_AfxDrawBorders(pDC, rc, (m_sBorderStyle == 1), (m_sAppearance == 1));
	OnDraw(pDC, rc, rc);
	if (! m_bOptimizedDraw)
		pDC->RestoreDC(iSaveDC);
}

void COleControl::DrawMetafile(CDC* pDC, CRect& rc)
{
	int iSaveDC;
	if (! m_bOptimizedDraw)
		iSaveDC = pDC->SaveDC();
	m_rcBounds = rc;
	_AfxDrawBorders(pDC, rc, (m_sBorderStyle == 1), (m_sAppearance == 1));
	OnDrawMetafile(pDC, rc);
	if (! m_bOptimizedDraw)
		pDC->RestoreDC(iSaveDC);
}

void COleControl::OnDraw(CDC*, const CRect&, const CRect&)
{
	// To be overridden by subclass.
}

void COleControl::OnDrawMetafile(CDC* pDC, const CRect& rcBounds)
{
	// By default, we draw into metafile the same way we would draw to the
	// screen.  This may be overridden by the subclass.

	OnDraw(pDC, rcBounds, rcBounds);
}

BOOL COleControl::GetMetafileData(LPFORMATETC lpFormatEtc,
		LPSTGMEDIUM lpStgMedium)
{
	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
	ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
	ASSERT(lpStgMedium->tymed == TYMED_NULL);   // GetDataHere not valid
	ASSERT(lpStgMedium->pUnkForRelease == NULL);

	// medium must be TYMED_MFPICT -- cannot fill in existing HGLOBAL
	if (!(lpFormatEtc->tymed & TYMED_MFPICT) || lpStgMedium->hGlobal != NULL)
		return FALSE;

	// create appropriate memory metafile DC
	CMetaFileDC dc;
	if (!dc.Create())
		return FALSE;

	// create attribute DC according to lpFormatEtc->ptd
	HDC hAttribDC = ::_AfxOleCreateDC(lpFormatEtc->ptd);
	dc.SetAttribDC(hAttribDC);

	// Paint directly into the metafile.
	int cx;
	int cy;
	GetControlSize(&cx, &cy);
	CRect rc(0, 0, cx, cy);
	dc.SetMapMode(MM_ANISOTROPIC);
	dc.SetWindowOrg(0, 0);
	dc.SetWindowExt(cx, cy);
	DrawMetafile(&dc, rc);

	// attribute DC is no longer necessary
	dc.SetAttribDC(NULL);
	::DeleteDC(hAttribDC);

	HMETAFILE hMF;
	hMF = (HMETAFILE)dc.Close();
	if (hMF == NULL)
		return FALSE;

	HGLOBAL hPict;
	if ((hPict = ::GlobalAlloc(GMEM_DDESHARE, sizeof(METAFILEPICT))) == NULL)
	{
		DeleteMetaFile(hMF);
		return FALSE;
	}
	LPMETAFILEPICT lpPict;
	if ((lpPict = (LPMETAFILEPICT)::GlobalLock(hPict)) == NULL)
	{
		DeleteMetaFile(hMF);
		::GlobalFree(hPict);
		return FALSE;
	}

	// set the metafile size
	lpPict->mm = MM_ANISOTROPIC;
	lpPict->hMF = hMF;
	lpPict->xExt = (int)m_cxExtent;
	lpPict->yExt = (int)m_cyExtent;

	// return the medium with the hGlobal to the METAFILEPICT
	::GlobalUnlock(hPict);
	lpStgMedium->hGlobal = hPict;
	lpStgMedium->tymed = TYMED_MFPICT;
	return TRUE;
}

BOOL COleControl::OnCreateAggregates()
{
	return TRUE;
}

LPVOID COleControl::QueryDefHandler(REFIID iid)
{
	// If we're being aggregated, we want to pass the outer unknown
	// to the object we're aggregating (the default handler).
	// Otherwise, we pass our own "inner" unknown.
	// That's what GetControllingUnknown() does.

	LPUNKNOWN pUnk = GetControllingUnknown();

	CLSID clsid;
	GetClassID(&clsid);

	if (m_pDefIUnknown == NULL)
	{
		// Note: This call will not increment pUnk's reference count.
		HRESULT hr = CreateDataCache(pUnk, clsid,
			IID_IUnknown, (LPLPVOID)&m_pDefIUnknown);

		if (FAILED(hr))
			return NULL;
	}

	LPVOID pNew;

	// Note: For the following QueryInterface call, we want to prevent
	// pUnk's reference count from being incremented.  So, if the
	// call succeeds, we immediately force a decrement of the reference count.

	if (SUCCEEDED(m_pDefIUnknown->QueryInterface(iid, &pNew)))
	{
		ASSERT(pNew != NULL);
		pUnk->Release();
	}

	return pNew;
}

void COleControl::InvalidateControl(LPCRECT lpRect, BOOL bErase)
{
	if (m_bInPlaceActive && m_bInPlaceSiteWndless)
	{
		CRect rect;
		if (lpRect != NULL)
		{
			CPoint point(0, 0);
			ClientToParent(m_rcPos, &point);
			rect.CopyRect(lpRect);
			rect.OffsetRect(point);
			lpRect = &rect;
		}
		m_pInPlaceSiteWndless->InvalidateRect(lpRect, bErase);
	}
	else if (m_bInPlaceActive || m_bOpen)
	{
		InvalidateRect(lpRect, bErase);
	}
	else
	{
		SendAdvise(OBJECTCODE_VIEWCHANGED);
	}

	SendAdvise(OBJECTCODE_DATACHANGED);
}

CWnd* COleControl::GetOuterWindow() const
{
	return (m_pReflect != NULL ? (CWnd*)m_pReflect : (CWnd*)this);
}

void COleControl::OnReflectorDestroyed()
{
	m_pReflect = NULL;
}

HRESULT COleControl::SaveState(IStream* pstm)
{
	HRESULT hr = S_OK;

	TRY
	{
		// Delegate to the Serialize method.
		COleStreamFile file(pstm);
		CArchive ar(&file, CArchive::store);
		Serialize(ar);
	}
	CATCH_ALL(e)
	{
		hr = E_FAIL;
		DELETE_EXCEPTION(e);
	}
	END_CATCH_ALL

	return hr;
}

HRESULT COleControl::LoadState(IStream* pstm)
{
	HRESULT hr = S_OK;

	TRY
	{
		// Delegate to the Serialize method.
		COleStreamFile file(pstm);
		CArchive ar(&file, CArchive::load);
		Serialize(ar);
	}
	CATCH_ALL(e)
	{
		// The load failed.  Delete any partially-initialized state.
		OnResetState();
		m_bInitialized = TRUE;
		hr = E_FAIL;
		DELETE_EXCEPTION(e);
	}
	END_CATCH_ALL

	// Clear the modified flag.
	m_bModified = FALSE;

	// Unless IOleObject::SetClientSite is called after this, we can
	// count on ambient properties being available while loading.
	m_bCountOnAmbients = TRUE;

	// Properties have been initialized
	m_bInitialized = TRUE;

	// Uncache cached ambient properties
	_afxAmbientCache->Cache(NULL);

	return hr;
}

void COleControl::SendAdvise(UINT uCode)
{
	// Calls the appropriate IOleClientSite or IAdviseSink member function
	// for various events such as closure, renaming, saving, etc.

	switch (uCode)
	{
	case OBJECTCODE_SAVED:
		if (m_pOleAdviseHolder != NULL)
			m_pOleAdviseHolder->SendOnSave();
		break;

	case OBJECTCODE_CLOSED:
		if (m_pOleAdviseHolder != NULL)
			m_pOleAdviseHolder->SendOnClose();
		break;

	case OBJECTCODE_SAVEOBJECT:
		if (m_bModified && m_pClientSite != NULL)
			m_pClientSite->SaveObject();
		break;

	case OBJECTCODE_DATACHANGED:
		//No flags are necessary here.
		if (m_pDataAdviseHolder != NULL)
			m_pDataAdviseHolder->SendOnDataChange(&m_xDataObject, 0, 0);
		break;

	case OBJECTCODE_SHOWWINDOW:
		if (m_pClientSite != NULL)
			m_pClientSite->OnShowWindow(TRUE);
		break;

	case OBJECTCODE_HIDEWINDOW:
		if (m_pClientSite != NULL)
			m_pClientSite->OnShowWindow(FALSE);
		break;

	case OBJECTCODE_SHOWOBJECT:
		if (m_pClientSite != NULL)
			m_pClientSite->ShowObject();
		break;

	case OBJECTCODE_VIEWCHANGED:
		{
			DWORD aspects;
			DWORD advf;
			LPADVISESINK pAdvSink;

			if (SUCCEEDED(m_xViewObject.GetAdvise(&aspects, &advf, &pAdvSink)) &&
				(pAdvSink != NULL))
			{
				pAdvSink->OnViewChange(DVASPECT_CONTENT, -1);
				pAdvSink->Release();
			}
		}
		break;
	}
}

HRESULT COleControl::OnHide()
{
	CWnd* pWnd = m_bOpen ? m_pWndOpenFrame : GetOuterWindow();
	if (pWnd != NULL && pWnd->m_hWnd != NULL)
	{
		if (m_bOpen)
			::ShowWindow(pWnd->m_hWnd, SW_HIDE);
		else
			::SetWindowPos(pWnd->m_hWnd, NULL, 0, 0, 0, 0,
				SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
				SWP_HIDEWINDOW);
		pWnd->SetParent(NULL);
	}

	RELEASE(m_pInPlaceFrame);
	RELEASE(m_pInPlaceDoc);

	if (m_bOpen)
		SendAdvise(OBJECTCODE_HIDEWINDOW);

	return S_OK;
}

void COleControl::ResizeFrameWindow(int cxCtrl, int cyCtrl)
{
	m_pWndOpenFrame->SetWindowPos(NULL, 0, 0, 100, 100,
				SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
	CRect rectClient;
	m_pWndOpenFrame->GetClientRect(&rectClient);
	CRect rectWindow;
	m_pWndOpenFrame->GetWindowRect(&rectWindow);
	int cx = cxCtrl + rectWindow.Width()  - rectClient.Width();
	int cy = cyCtrl + rectWindow.Height() - rectClient.Height();
	m_pWndOpenFrame->SetWindowPos(NULL, 0, 0, cx, cy,
				SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
}

HRESULT COleControl::OnOpen(BOOL bTryInPlace, LPMSG pMsg)
{
	if (!m_bOpen)
	{
		// If not already open, try in-place activating.

		if (bTryInPlace && SUCCEEDED(OnActivateInPlace(TRUE, pMsg)))
			return S_OK;

		// If already in-place active, deactivate first.
		if (m_bInPlaceActive)
			m_xOleInPlaceObject.InPlaceDeactivate();

		m_bOpen = TRUE;

		// Open a separate window.
		if (m_pWndOpenFrame == NULL)
		{
			// Create frame window
			m_pWndOpenFrame = CreateFrameWindow();

			if (m_pWndOpenFrame == NULL)
				return E_FAIL;

			// Size frame window to exactly contain the control.
			int cx;
			int cy;
			GetControlSize(&cx, &cy);
			ResizeFrameWindow(cx, cy);

			// Create and/or reparent the control's window.
			CRect rectClient;
			m_pWndOpenFrame->GetClientRect(&rectClient);
			if (!CreateControlWindow(m_pWndOpenFrame->m_hWnd, rectClient))
				return E_FAIL;
		}
	}

	// Make the frame window visible and activate it.
	ASSERT(m_pWndOpenFrame != NULL);
	m_pWndOpenFrame->ShowWindow(SW_SHOW);
	m_pWndOpenFrame->SetActiveWindow();
	SendAdvise(OBJECTCODE_SHOWWINDOW);

	return S_OK;
}

CControlFrameWnd* COleControl::CreateFrameWindow()
{
	TCHAR szUserType[256];
	GetUserType(szUserType);

	CControlFrameWnd* pWnd = new CControlFrameWnd(this);
	if (!pWnd->Create(szUserType))
	{
		// If Create failed, then frame window has deleted itself.
		pWnd = NULL;
	}

	return pWnd;
}

void COleControl::OnFrameClose()
{
	// Reparent control to prevent its window from being destroyed.
	CWnd* pWnd = GetOuterWindow();
	if (pWnd != NULL)
	{
		::SetWindowPos(pWnd->m_hWnd, NULL, 0, 0, 0, 0,
			SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
			SWP_HIDEWINDOW);
		pWnd->SetParent(NULL);
	}

	m_pWndOpenFrame = NULL;
	m_bOpen = FALSE;

	m_xOleObject.Close(OLECLOSE_SAVEIFDIRTY);

	SendAdvise(OBJECTCODE_HIDEWINDOW);
	SendAdvise(OBJECTCODE_CLOSED);
}

BOOL COleControl::GetRectInContainer(LPRECT lpRect)
{
	if (m_bInPlaceActive)
		CopyRect(lpRect, &m_rcPos);

	return m_bInPlaceActive;
}

LPCLSID COleControl::GetPropPageIDs(ULONG& cPropPages)
{
	cPropPages = 0;
	return NULL;
}

BOOL COleControl::OnEdit(LPMSG lpMsg, HWND, LPCRECT lpRect)
{
	CopyRect(m_rcPos, lpRect);
	return SUCCEEDED(OnActivateInPlace(TRUE, lpMsg));
}

HWND AFXAPI _AfxGetTopLevelWindow(HWND hWnd)
{
	HWND hWndTop;

	do
	{
		hWndTop = hWnd;
		hWnd = ::GetParent(hWnd);
	}
	while (hWnd != NULL);

	return hWndTop;
}

BOOL COleControl::OnProperties(LPMSG, HWND hWndParent, LPCRECT)
{
	USES_CONVERSION;

	HRESULT hr;

	if ((m_pControlSite == NULL) ||
		FAILED(hr = m_pControlSite->ShowPropertyFrame()))
	{
		LPUNKNOWN pUnk = GetIDispatch(FALSE);
		CWnd* pWndOwner = CWnd::GetSafeOwner(CWnd::FromHandle(hWndParent));
		HWND hWndOwner = pWndOwner->GetSafeHwnd();

		LCID lcid = AmbientLocaleID();

		ULONG cPropPages;
		LPCLSID pclsidPropPages = GetPropPageIDs(cPropPages);

		RECT rectParent;
		RECT rectTop;
		::GetWindowRect(hWndParent, &rectParent);
		::GetWindowRect(hWndOwner, &rectTop);

		TCHAR szUserType[256];
		GetUserType(szUserType);

		PreModalDialog(hWndOwner);
		hr = OleCreatePropertyFrame(hWndOwner, rectParent.left - rectTop.left,
				rectParent.top - rectTop.top, T2COLE(szUserType), 1, &pUnk,
				cPropPages, pclsidPropPages, lcid, NULL, 0);
		PostModalDialog(hWndOwner);
	}

	return SUCCEEDED(hr);
}

static HDC PASCAL _AfxFastBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaintStruct)
{
	// hide caret
	HideCaret(hWnd);

	// create DC
	HDC hDC = lpPaintStruct->hdc = GetDC(hWnd);

	// select clip region
	HRGN hRgnUpdate = CreateRectRgn(0, 0, 0, 0);
	GetUpdateRgn(hWnd, hRgnUpdate, FALSE);
	SelectClipRgn(hDC, hRgnUpdate);
	DeleteObject(hRgnUpdate);
	GetClipBox(hDC, &lpPaintStruct->rcPaint);

	// validate window
	ValidateRect(hWnd, NULL);

	// fill paint struct and return
	lpPaintStruct->fIncUpdate = lpPaintStruct->fRestore = FALSE;
	lpPaintStruct->fErase = TRUE;
	return lpPaintStruct->hdc;
}

static BOOL PASCAL _AfxFastEndPaint(HWND hWnd, const PAINTSTRUCT FAR* lpPaintStruct)
{
	ReleaseDC(hWnd, lpPaintStruct->hdc);
	ShowCaret(hWnd);
	return TRUE;
}

DWORD COleControl::GetControlFlags()
{
	return fastBeginPaint | clipPaintDC;
}

void COleControl::OnPaint(CDC* pDC)
{
	if (m_bNoRedraw)
	{
		// flicker-free activation: no need to repaint
		ValidateRect(NULL);
		m_bNoRedraw = FALSE;    // one time only
		return;
	}

	AfxLockTempMaps();

	GetWindowRect(m_rcBounds);
	m_rcBounds.OffsetRect(-m_rcBounds.left, -m_rcBounds.top);

	// Adjust bounds for size of UI Active tracker, if any.
	if (!m_bOpen && (m_pRectTracker != NULL))
	{
		int nHandleSize = (int)m_pRectTracker->m_nHandleSize - 1;
		m_rcBounds.InflateRect(-nHandleSize, -nHandleSize);
	}

	CRect rcClient;
	GetClientRect(rcClient);

	if (pDC != NULL)
	{
		// We were passed a device context: use it.
		int iSaveDC = pDC->SaveDC();
		OnDraw(pDC, rcClient, rcClient);
		pDC->RestoreDC(iSaveDC);
	}
	else
	{
		// Create a device context for painting.
		int nFlags = GetControlFlags();
		if (nFlags & fastBeginPaint)
		{
			PAINTSTRUCT ps;
			HDC hDC = _AfxFastBeginPaint(m_hWnd, &ps);
			CDC dc;
			dc.Attach(hDC);
			if (nFlags & clipPaintDC)
				dc.IntersectClipRect(rcClient);
			OnDraw(&dc, rcClient, &ps.rcPaint);
			dc.Detach();
			_AfxFastEndPaint(m_hWnd, &ps);
		}
		else
		{
			CPaintDC dc(this);
			OnDraw(&dc, rcClient, &dc.m_ps.rcPaint);
		}
	}

	AfxUnlockTempMaps();
}

void  COleControl::Serialize(CArchive& ar)
{
	CArchivePropExchange px(ar);
	DoPropExchange(&px);
	if (ar.IsLoading())
	{
		BoundPropertyChanged(DISPID_UNKNOWN);
		InvalidateControl();
	}
}

void COleControl::DoPropExchange(CPropExchange* pPX)
{
	ASSERT_POINTER(pPX, CPropExchange);

	ExchangeExtent(pPX);
	ExchangeStockProps(pPX);
}

/////////////////////////////////////////////////////////////////////////////
// Wrappers for IOleControlSite

void COleControl::ControlInfoChanged()
{
	if (m_pControlSite != NULL)
		m_pControlSite->OnControlInfoChanged();
}

BOOL COleControl::LockInPlaceActive(BOOL bLock)
{
	if (m_pControlSite != NULL)
		return SUCCEEDED(m_pControlSite->LockInPlaceActive(bLock));

	return FALSE;
}

LPDISPATCH COleControl::GetExtendedControl()
{
	LPDISPATCH pDispatch = NULL;
	if (m_pControlSite != NULL)
		m_pControlSite->GetExtendedControl(&pDispatch);

	return pDispatch;
}

void COleControl::TransformCoords(POINTL* lpptlHimetric,
	POINTF* lpptfContainer, DWORD flags)
{
	if ((m_pControlSite == NULL) ||
		(FAILED(m_pControlSite->TransformCoords(lpptlHimetric,
			lpptfContainer, flags))))
	{
		// Transformation failed, use the identity transformation

		if (flags & XFORMCOORDS_CONTAINERTOHIMETRIC)
		{
			lpptlHimetric->x = (long)lpptfContainer->x;
			lpptlHimetric->y = (long)lpptfContainer->y;
		}
		else
		{
			lpptfContainer->x = (float)lpptlHimetric->x;
			lpptfContainer->y = (float)lpptlHimetric->y;
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::XOleControl

STDMETHODIMP_(ULONG) COleControl::XOleControl::AddRef()
{
	METHOD_PROLOGUE_EX_(COleControl, OleControl)
	return (ULONG)pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) COleControl::XOleControl::Release()
{
	METHOD_PROLOGUE_EX_(COleControl, OleControl)
	return (ULONG)pThis->ExternalRelease();
}

STDMETHODIMP COleControl::XOleControl::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX_(COleControl, OleControl)
	return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP COleControl::XOleControl::GetControlInfo(LPCONTROLINFO pCI)
{
	METHOD_PROLOGUE_EX(COleControl, OleControl)
	pThis->OnGetControlInfo(pCI);
	return S_OK;
}

STDMETHODIMP COleControl::XOleControl::OnMnemonic(LPMSG pMsg)
{
	METHOD_PROLOGUE_EX(COleControl, OleControl)
	pThis->OnMnemonic(pMsg);
	return S_OK;
}

STDMETHODIMP COleControl::XOleControl::OnAmbientPropertyChange(DISPID dispid)
{
	METHOD_PROLOGUE_EX(COleControl, OleControl)

	if (dispid == DISPID_AMBIENT_UIDEAD || dispid == DISPID_UNKNOWN)
		pThis->m_bUIDead = (BYTE)(pThis->AmbientUIDead());

	pThis->OnAmbientPropertyChange(dispid);
	return S_OK;
}

STDMETHODIMP COleControl::XOleControl::FreezeEvents(BOOL bFreeze)
{
	METHOD_PROLOGUE_EX(COleControl, OleControl)

	ULONG& cEventsFrozen = pThis->m_cEventsFrozen;

	if (bFreeze)
		++(cEventsFrozen);
	else
		--(cEventsFrozen);

	ASSERT(cEventsFrozen >= 0); // Should never go below zero!

	if ((cEventsFrozen == 1 && bFreeze) ||
		(cEventsFrozen == 0 && !bFreeze))
	{
		pThis->OnFreezeEvents(bFreeze);
	}

	return S_OK;
}

void COleControl::OnGetControlInfo(LPCONTROLINFO pControlInfo)
{
	// Subclass may override

	pControlInfo->hAccel = NULL;
	pControlInfo->cAccel = 0;
	pControlInfo->dwFlags = 0;
}

void COleControl::OnMnemonic(LPMSG)
{
	// To be implemented by subclass
}

void COleControl::OnAmbientPropertyChange(DISPID)
{
	// To be implemented by subclass
}

void COleControl::OnFreezeEvents(BOOL)
{
	// To be implemented by subclass
}

void COleControl::OnSetClientSite()
{
#ifndef _MAC
	if (!m_bDataPathPropertiesLoaded)
	{
		CAsyncPropExchange PX(m_dwDataPathVersionToReport);
		DoPropExchange(&PX);
		m_bDataPathPropertiesLoaded=TRUE;
	}
#endif
}

LPOLECLIENTSITE COleControl::GetClientSite()
{
	return m_pClientSite;
}

COLORREF COleControl::TranslateColor(OLE_COLOR clrColor, HPALETTE hpal)
{
	COLORREF cr = RGB(0x00,0x00,0x00);
	OleTranslateColor(clrColor, hpal, &cr);
	return cr;
}

void COleControl::Refresh()
{
	InvalidateControl();
	if (m_hWnd != NULL)
		UpdateWindow();
}

void COleControl::DoClick()
{
	OnClick(LEFT_BUTTON);
}

BOOL COleControl::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (m_pReflect != NULL)
		m_pReflect->SetControl(this);

	return CWnd::OnNcCreate(lpCreateStruct);
}

void COleControl::RecreateControlWindow()
{
	if (m_bInPlaceActive)
	{
		BOOL bUIActive = m_bUIActive;
		m_xOleInPlaceObject.InPlaceDeactivate();
		DestroyWindow();
		OnActivateInPlace(bUIActive, NULL);
	}
	else if (m_bOpen)
	{
		DestroyWindow();
		CRect rectClient;
		m_pWndOpenFrame->GetClientRect(&rectClient);
		CreateControlWindow(m_pWndOpenFrame->m_hWnd, rectClient);
	}
	else
	{
		HWND hWndParent = GetParkingWindow();
		if (hWndParent != NULL)
		{
			DestroyWindow();
			int cx;
			int cy;
			GetControlSize(&cx, &cy);
			CRect rect(0, 0, cx, cy);
			CreateControlWindow(hWndParent, rect);
		}
	}
}

void COleControl::CreateWindowForSubclassedControl()
{
	if (IsSubclassedControl() && (m_hWnd == NULL))
	{
		// If this is a subclassed control, we should create the window
		// for it now, in case the window is needed by the DoSuperclassPaint
		// implementation.

		HWND hWndParent = GetParkingWindow();
		if (hWndParent != NULL)
		{
			SIZEL szlHimetric;
			SIZEL szlPixels;
			szlHimetric.cx = m_cxExtent;
			szlHimetric.cy = m_cyExtent;
			_AfxXformSizeInHimetricToPixels(NULL, &szlHimetric, &szlPixels);
			CRect rcPos(0, 0, (int)szlPixels.cx, (int)szlPixels.cy);
			CreateControlWindow(hWndParent, rcPos);
		}
	}
}

int COleControl::OnMouseActivate(CWnd *pDesktopWnd, UINT nHitTest, UINT message)
{
	if (m_bInPlaceActive && !m_bUIActive)
		m_bPendingUIActivation = TRUE;

	return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message );
}

void COleControl::PreModalDialog(HWND hWndParent)
{
	if (m_pInPlaceFrame != NULL)
	{
		m_pInPlaceFrame->EnableModeless(FALSE);
	}
	else
	{
		HWND hWndTop = _AfxGetTopLevelWindow(hWndParent);
		if (hWndTop != NULL)
			::EnableWindow(hWndTop, FALSE);
	}
}

void COleControl::PostModalDialog(HWND hWndParent)
{
	if (m_pInPlaceFrame != NULL)
	{
		m_pInPlaceFrame->EnableModeless(TRUE);
	}
	else
	{
		HWND hWndTop = _AfxGetTopLevelWindow(hWndParent);
		if (hWndTop != NULL)
			::EnableWindow(hWndTop, TRUE);
	}
}

void COleControl::SetModifiedFlag(BOOL bModified)
{
	m_bModified = (BYTE)bModified;
}

BOOL COleControl::IsModified()
{
	return m_bModified;
}

BOOL COleControl::WillAmbientsBeValidDuringLoad()
{
	return m_bCountOnAmbients;
}

void COleControl::EnableSimpleFrame()
{
	m_bSimpleFrame = TRUE;
}

BOOL COleControl::IgnoreWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam,
	LRESULT* plResult)
{
	if (!m_bUIDead)
		return FALSE;

	switch (msg)
	{
	case WM_NCHITTEST:
		*plResult = HTNOWHERE;
		return TRUE;

	case WM_SETCURSOR:
		*plResult = ::SendMessage(::GetParent(m_hWnd), msg, wParam, lParam);
		return TRUE;
	}

	if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST))
	{
		*plResult = 0;
		return TRUE;
	}

	return FALSE;
}

LRESULT COleControl::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
	DWORD dwCookie;
	LRESULT lResult;
	HRESULT hr;

	ExternalAddRef();   // "Insurance" addref -- keeps control alive

	// allow OCM_ reflections to be handled by ON_XXX_REFLECT macros
	switch (msg)
	{
	case OCM_COMMAND:
	case OCM_CTLCOLORBTN:
	case OCM_CTLCOLOREDIT:
	case OCM_CTLCOLORDLG:
	case OCM_CTLCOLORLISTBOX:
	case OCM_CTLCOLORMSGBOX:
	case OCM_CTLCOLORSCROLLBAR:
	case OCM_CTLCOLORSTATIC:
	case OCM_DRAWITEM:
	case OCM_MEASUREITEM:
	case OCM_DELETEITEM:
	case OCM_VKEYTOITEM:
	case OCM_CHARTOITEM:
	case OCM_COMPAREITEM:
	case OCM_HSCROLL:
	case OCM_VSCROLL:
	case OCM_PARENTNOTIFY:
	case OCM_NOTIFY:
		if (ReflectChildNotify(msg-OCM__BASE, wParam, lParam, &lResult))
		{
			ExternalRelease();
			return lResult;
		}
	}

	// Give the simple frame site the opportunity to filter the message
	if ((m_pSimpleFrameSite != NULL) &&
		SUCCEEDED(hr = m_pSimpleFrameSite->PreMessageFilter(
			m_hWnd, msg, wParam, lParam, &lResult, &dwCookie)))
	{
		if (hr == S_OK)
		{
			if (!IgnoreWindowMessage(msg, wParam, lParam, &lResult))
				lResult = CWnd::WindowProc(msg, wParam, lParam);

			// Simple frame site may have been cleared...
			// check before calling again.

			if (m_pSimpleFrameSite != NULL)
				m_pSimpleFrameSite->PostMessageFilter(
					m_hWnd, msg, wParam, lParam, &lResult, dwCookie);
		}
	}
	else
	{
		if (!IgnoreWindowMessage(msg, wParam, lParam, &lResult))
			lResult = CWnd::WindowProc(msg, wParam, lParam);
	}

	ExternalRelease();

	return lResult;
}

LRESULT COleControl::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	if (m_hWnd != NULL)
		return CWnd::DefWindowProc(nMsg, wParam, lParam);
	else
		return 0;
}

int COleControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (IsSubclassedControl())
		return CWnd::OnCreate(lpCreateStruct);
	else
		return 0;
}

void COleControl::OnSize(UINT nType, int cx, int cy)
{
	if (IsSubclassedControl())
		CWnd::OnSize(nType, cx, cy);
}

void COleControl::OnMove(int x, int y)
{
	if (IsSubclassedControl())
		CWnd::OnMove(x, y);
}

void COleControl::OnShowWindow(BOOL bShow, UINT nStatus)
{
	if (IsSubclassedControl())
		CWnd::OnShowWindow(bShow, nStatus);
}

/////////////////////////////////////////////////////////////////////////////
// Command prompts

void COleControl::OnInitMenuPopup(CMenu* pMenu, UINT, BOOL bSysMenu)
{
	AfxCancelModes(m_hWnd);

	if (bSysMenu)
		return;     // don't support system menu

	ASSERT(pMenu != NULL);
	// check the enabled state of various menu items

	CCmdUI state;
	state.m_pMenu = pMenu;
	ASSERT(state.m_pOther == NULL);
	ASSERT(state.m_pParentMenu == NULL);

	// determine if menu is popup in top-level menu and set m_pOther to
	// it if so (m_pParentMenu == NULL indicates that it is secondary popup)
	HMENU hParentMenu;
	if (_afxTrackingMenu == pMenu->m_hMenu)
		state.m_pParentMenu = pMenu;    // parent == child for tracking popup
	else
	{
		CWnd* pParent = GetTopLevelParent();
			// child windows don't have menus -- need to go to the top!
		if (pParent != NULL &&
			(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
		{
			int nIndexMax = ::GetMenuItemCount(hParentMenu);
			for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
			{
				if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
				{
					// when popup is found, m_pParentMenu is containing menu
					state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
					break;
				}
			}
		}
	}

	state.m_nIndexMax = pMenu->GetMenuItemCount();
	for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
	  state.m_nIndex++)
	{
		state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
		if (state.m_nID == 0)
			continue; // menu separator or invalid cmd - ignore it

		ASSERT(state.m_pOther == NULL);
		ASSERT(state.m_pMenu != NULL);
		if (state.m_nID == (UINT)-1)
		{
			// possibly a popup menu, route to first item of that popup
			state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
			if (state.m_pSubMenu == NULL ||
				(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
				state.m_nID == (UINT)-1)
			{
				continue;       // first item of popup can't be routed to
			}
			state.DoUpdate(this, FALSE);    // popups are never auto disabled
		}
		else
		{
			// normal menu item
			// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
			// set and command is _not_ a system command.
			state.m_pSubMenu = NULL;
			state.DoUpdate(this, m_bAutoMenuEnable && state.m_nID < 0xF000);
		}
	}
}

void COleControl::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU /*hSysMenu*/)
{
	// set the tracking state (update on idle)
	if (nFlags == 0xFFFF)
	{
		m_nIDTracking = AFX_IDS_IDLEMESSAGE;
		SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
		ASSERT(m_nIDTracking == m_nIDLastMessage);
	}
	else if (nItemID == 0 ||
		nFlags & (MF_SEPARATOR|MF_POPUP|MF_MENUBREAK|MF_MENUBARBREAK))
	{
		// nothing should be displayed
		m_nIDTracking = 0;
	}
	else if (nItemID >= 0xF000 && nItemID < 0xF1F0) // max of 31 SC_s
	{
		// special strings table entries for system commands
		m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);
		ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST &&
			m_nIDTracking < AFX_IDS_SCFIRST + 31);
	}
	else if (nItemID >= AFX_IDM_FIRST_MDICHILD)
	{
		// all MDI Child windows map to the same help id
		m_nIDTracking = AFX_IDS_MDICHILD;
	}
	else
	{
		// track on idle
		m_nIDTracking = nItemID;
	}

	// when running in-place, it is necessary to cause a message to
	// be pumped through the queue.
	if (m_nIDTracking != m_nIDLastMessage && GetParent() != NULL)
		PostMessage(WM_NULL);
}

void COleControl::GetMessageString(UINT nID, CString& rMessage) const
{
	// load appropriate string
	LPTSTR lpsz = rMessage.GetBuffer(255);
	if (AfxLoadString(nID, lpsz) != 0)
	{
		// first newline terminates actual string
		lpsz = _tcschr(lpsz, '\n');
		if (lpsz != NULL)
			*lpsz = '\0';
	}
	else
	{
		// not found
		TRACE1("Warning: no message line prompt for ID 0x%04X.\n", nID);
	}
	rMessage.ReleaseBuffer();
}

LRESULT COleControl::OnSetMessageString(WPARAM wParam, LPARAM lParam)
{
	USES_CONVERSION;

	if (m_pInPlaceFrame != NULL)
	{
		LPCTSTR lpsz = NULL;
		CString strMessage;

		// set the message bar text
		if (lParam != 0)
		{
			ASSERT(wParam == 0);    // can't have both an ID and a string
			lpsz = (LPCTSTR)lParam; // set an explicit string
		}
		else if (wParam != 0)
		{
			// use the wParam as a string ID
			GetMessageString(wParam, strMessage);
			lpsz = strMessage;
		}

		// notify container of new status text
		m_pInPlaceFrame->SetStatusText(T2COLE(lpsz));
	}

	UINT nIDLast = m_nIDLastMessage;
	m_nIDLastMessage = (UINT)wParam;    // new ID (or 0)
	m_nIDTracking = (UINT)wParam;       // so F1 on toolbar buttons work
	return nIDLast;
}

void COleControl::OnEnterIdle(UINT nWhy, CWnd* /*pWho*/)
{
	if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
		return;

	SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
	ASSERT(m_nIDTracking == m_nIDLastMessage);
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::XSpecifyPropertyPages

STDMETHODIMP_(ULONG) COleControl::XSpecifyPropertyPages::AddRef()
{
	// Delegate to our exported AddRef.
	METHOD_PROLOGUE_EX_(COleControl, SpecifyPropertyPages)
	return (ULONG)pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) COleControl::XSpecifyPropertyPages::Release()
{
	// Delegate to our exported Release.
	METHOD_PROLOGUE_EX_(COleControl, SpecifyPropertyPages)
	return (ULONG)pThis->ExternalRelease();
}

STDMETHODIMP COleControl::XSpecifyPropertyPages::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	// Delegate to our exported QueryInterface.
	METHOD_PROLOGUE_EX_(COleControl, SpecifyPropertyPages)
	return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP COleControl::XSpecifyPropertyPages::GetPages(CAUUID* pPages)
{
	METHOD_PROLOGUE_EX(COleControl, SpecifyPropertyPages)

	ASSERT(pPages != NULL);

	if (pPages == NULL)
		return E_POINTER;

	pPages->cElems = 0;
	pPages->pElems = NULL;

	HRESULT hr = E_OUTOFMEMORY;
	ULONG cElems;
	LPCLSID pClassID = pThis->GetPropPageIDs(cElems);

	if ((pPages->pElems = (LPCLSID)(CoTaskMemAlloc(cElems * sizeof(CLSID)))) != NULL)
	{
		ASSERT(pPages->pElems != NULL);
		pPages->cElems = cElems;
		memcpy(pPages->pElems, pClassID, (int)(cElems * sizeof(CLSID)));
		hr = S_OK;
	}
	return hr;
}

void COleControl::OnDestroy()
{
	// Release hfont, if any.
	if (m_hFontPrev != NULL)
	{
		SendMessage(WM_SETFONT, (WPARAM)NULL, 0);
		InternalGetFont().m_pFont->ReleaseHfont(m_hFontPrev);
		m_hFontPrev = NULL;
	}

	CWnd::OnDestroy();
}

void COleControl::OnKillFocus(CWnd* pNewWnd)
{
	CWnd::OnKillFocus(pNewWnd);

	if (m_pControlSite != NULL)
		m_pControlSite->OnFocus(FALSE);
}

void COleControl::OnSetFocus(CWnd* pOldWnd)
{
	CWnd::OnSetFocus(pOldWnd);

	if (m_pControlSite != NULL)
		m_pControlSite->OnFocus(TRUE);
}

LRESULT COleControl::OnOcmCtlColorBtn(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORBTN, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorDlg(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORDLG, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorEdit(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLOREDIT, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorListBox(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORLISTBOX, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorMsgBox(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORMSGBOX, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorScrollBar(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORSCROLLBAR, wParam, lParam);
}

LRESULT COleControl::OnOcmCtlColorStatic(WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(m_hWnd, WM_CTLCOLORSTATIC, wParam, lParam);
}

void COleControl::ThrowError(SCODE sc, UINT nDescriptionID, UINT nHelpID)
{
	TCHAR szBuffer[256];
	AfxLoadString(nDescriptionID, szBuffer);
	if (nHelpID == -1)
		nHelpID = nDescriptionID;
	ThrowError(sc, szBuffer, nHelpID);
}

void COleControl::ThrowError(SCODE sc, LPCTSTR pszDescription, UINT nHelpID)
{
	COleDispatchException* pExcept = new COleDispatchException(pszDescription,
		nHelpID, 0);
	pExcept->m_scError = sc;
	THROW(pExcept);
}

BOOL COleControl::IsInvokeAllowed(DISPID)
{
	return m_bInitialized;
}

/////////////////////////////////////////////////////////////////////////////
// Force any extra compiler-generated code into AFX_INIT_SEG

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(COleControl, CWnd)