home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
ctlcore.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
51KB
|
2,092 lines
// 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 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();
AFX_STATIC HWND AFXAPI _AfxGetParkingWindow()
{
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
ASSERT(pThreadState != NULL);
if (pThreadState->m_pWndPark == NULL)
{
AFX_MANAGE_STATE(_AfxGetOleModuleState());
CWnd* pWndTmp = NULL;
TRY
{
#ifdef _DEBUG
HWND hWndActive = ::GetActiveWindow();
#endif
pWndTmp = new CParkingWnd;
ASSERT(pWndTmp->m_hWnd != NULL);
#ifdef _DEBUG
ASSERT(hWndActive == ::GetActiveWindow());
#endif
}
CATCH_ALL(e)
{
if (pWndTmp)
delete pWndTmp;
pWndTmp = NULL;
}
END_CATCH_ALL
pThreadState->m_pWndPark = pWndTmp;
}
return pThreadState->m_pWndPark->GetSafeHwnd();
}
AFX_STATIC void AFXAPI _AfxReleaseParkingWindow()
{
_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_ERASEBKGND()
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() :
#ifdef _AFXDLL
m_font(&m_xFontNotification)
#else
m_font(NULL)
#endif
{
// 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_pRectTracker = 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_bPendingUIActivation = FALSE;
#ifdef _AFXDLL
m_bOpen = FALSE;
m_pWndOpenFrame = NULL;
#endif
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();
#ifdef _AFXDLL
if (m_pWndOpenFrame != NULL)
m_pWndOpenFrame->DestroyWindow();
#endif
ReleaseCaches();
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)
_AfxReleaseParkingWindow();
AfxOleUnlockApp();
}
void COleControl::ReleaseCaches()
{
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();
RELEASE(m_pDefIPersistStorage);
}
if (m_pDefIViewObject != NULL)
{
pUnk->AddRef();
RELEASE(m_pDefIViewObject);
}
if (m_pDefIOleCache != NULL)
{
pUnk->AddRef();
RELEASE(m_pDefIOleCache);
}
if (m_pAdviseInfo != NULL)
{
RELEASE(m_pAdviseInfo->m_pAdvSink);
delete m_pAdviseInfo;
m_pAdviseInfo = NULL;
}
RELEASE(m_pDefIUnknown);
InterlockedDecrement(&m_dwRef);
}
void COleControl::OnFinalRelease()
{
if (!m_bFinalReleaseCalled)
{
m_bFinalReleaseCalled = TRUE;
ReleaseCaches();
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;
#ifdef _AFXDLL
dc << "\nm_bOpen = " << m_bOpen;
#endif
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 prcClip)
{
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.
VERIFY(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 (prcClip == NULL)
prcClip = rcPos;
if (!m_pReflect->Create(prcClip, 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 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);
// And then reposition it...
OnSetObjectRects(rcPos, prcClip);
}
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));
}
BOOL COleControl::SetRectInContainer(LPCRECT lpRect)
{
if ((m_pInPlaceSite != NULL) && m_bInPlaceActive)
{
m_pInPlaceSite->OnPosRectChange(lpRect);
return TRUE;
}
#ifdef _AFXDLL
else if (m_bOpen)
{
ResizeOpenControl(lpRect->right - lpRect->left,
lpRect->bottom - lpRect->top);
return TRUE;
}
#endif
return FALSE;
}
void COleControl::OnResetState()
{
CResetPropExchange px;
DoPropExchange(&px);
InvalidateControl();
}
#ifndef BDR_INNER
#define BDR_INNER 0x000c
#endif
#ifndef BDR_OUTER
#define BDR_OUTER 0x0003
#endif
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 = 0;
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 && iSaveDC != 0)
pDC->RestoreDC(iSaveDC);
}
void COleControl::DrawMetafile(CDC* pDC, CRect& rc)
{
int iSaveDC = 0;
if (! m_bOptimizedDraw)
iSaveDC = pDC->SaveDC();
m_rcBounds = rc;
_AfxDrawBorders(pDC, rc, (m_sBorderStyle == 1), (m_sAppearance == 1));
OnDrawMetafile(pDC, rc);
if (! m_bOptimizedDraw && iSaveDC != 0)
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 = ▭
}
m_pInPlaceSiteWndless->InvalidateRect(lpRect, bErase);
}
#ifdef _AFXDLL
else if (m_bInPlaceActive || m_bOpen)
#else
else if (m_bInPlaceActive)
#endif
{
InvalidateRect(lpRect, bErase);
}
else
{
SendAdvise(OBJECTCODE_VIEWCHANGED);
}
if (m_bModified)
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()
{
#ifdef _AFXDLL
CWnd* pWnd = m_bOpen ? m_pWndOpenFrame : GetOuterWindow();
#else
CWnd* pWnd = GetOuterWindow();
#endif
if (pWnd != NULL && pWnd->m_hWnd != NULL)
::ShowWindow(pWnd->m_hWnd, SW_HIDE);
RELEASE(m_pInPlaceFrame);
RELEASE(m_pInPlaceDoc);
#ifdef _AFXDLL
if (m_bOpen)
SendAdvise(OBJECTCODE_HIDEWINDOW);
#endif
return S_OK;
}
HRESULT COleControl::OnOpen(BOOL bTryInPlace, LPMSG pMsg)
{
#ifndef _AFXDLL
ASSERT(bTryInPlace); // fully-open mode not supported in static builds
UNUSED_ALWAYS(bTryInPlace);
#endif
#ifndef _AFXDLL
return OnActivateInPlace(TRUE, pMsg);
#else
if (!m_bOpen)
{
// If not already open, try in-place activating.
if (bTryInPlace && SUCCEEDED(OnActivateInPlace(bTryInPlace, 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, 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;
#endif
}
#ifdef _AFXDLL
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);
}
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);
}
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);
}
#endif //_AFXDLL
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);
HWND hWndOwner = CWnd::GetSafeOwner_(hWndParent, NULL);
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);
}
DWORD COleControl::GetControlFlags()
{
return 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.
#ifdef _AFXDLL
if (!m_bOpen && (m_pRectTracker != NULL))
#else
if (m_pRectTracker != NULL)
#endif
{
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
{
#ifdef _DEBUG
int nFlags = GetControlFlags();
if (nFlags & fastBeginPaint)
TRACE0("Warning: COleControl::fastBeginPaint is obsolete.\n");
#endif
CPaintDC dc(this);
OnDraw(&dc, rcClient, &dc.m_ps.rcPaint);
}
AfxUnlockTempMaps();
}
BOOL COleControl::OnEraseBkgnd(CDC* pDC)
{
// do nothing -- controls erase their background in their OnDraw
if (IsSubclassedControl())
return CWnd::OnEraseBkgnd(pDC);
else
return TRUE;
}
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()
{
if (!m_bDataPathPropertiesLoaded)
{
CAsyncPropExchange PX(m_dwDataPathVersionToReport);
DoPropExchange(&PX);
m_bDataPathPropertiesLoaded=TRUE;
}
}
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);
}
#ifdef _AFXDLL
else if (m_bOpen)
{
DestroyWindow();
CRect rectClient;
m_pWndOpenFrame->GetClientRect(&rectClient);
CreateControlWindow(m_pWndOpenFrame->m_hWnd, rectClient, rectClient);
}
#endif //_AFXDLL
else
{
HWND hWndParent = _AfxGetParkingWindow();
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 = _AfxGetParkingWindow();
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 = S_OK;
ULONG cElems;
LPCLSID pClassID = pThis->GetPropPageIDs(cElems);
if (cElems > 0)
{
if ((pPages->pElems = (LPCLSID)(CoTaskMemAlloc(cElems * sizeof(CLSID)))) != NULL)
{
ASSERT(pPages->pElems != NULL);
pPages->cElems = cElems;
memcpy(pPages->pElems, pClassID, (int)(cElems * sizeof(CLSID)));
}
else
hr = E_OUTOFMEMORY;
}
else
{
pPages->cElems = 0;
pPages->pElems = NULL;
}
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)