home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
ctlinplc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
16KB
|
643 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_CORE2_SEG
#pragma code_seg(AFXCTL_CORE2_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
struct _AFXCTL_UIACTIVE_INFO
{
OLEMENUGROUPWIDTHS m_menuWidths;
HMENU m_hSharedMenu;
HOLEMENU m_hOleMenu;
_AFXCTL_UIACTIVE_INFO(HMENU hInPlaceMenu, LPOLEINPLACEFRAME pInPlaceFrame);
~_AFXCTL_UIACTIVE_INFO();
};
_AFXCTL_UIACTIVE_INFO::_AFXCTL_UIACTIVE_INFO(HMENU hInPlaceMenu,
LPOLEINPLACEFRAME pInPlaceFrame)
{
memset(&m_menuWidths, 0, sizeof m_menuWidths);
m_hSharedMenu = NULL;
m_hOleMenu = NULL;
if (hInPlaceMenu != NULL)
{
// Create shared menu
if ((m_hSharedMenu = ::CreateMenu()) == NULL)
return;
// Start out by getting menu from container
if (pInPlaceFrame->InsertMenus(m_hSharedMenu, &m_menuWidths) != S_OK)
{
::DestroyMenu(m_hSharedMenu);
m_hSharedMenu = NULL;
}
else
{
// Container shouldn't touch these
ASSERT(m_menuWidths.width[1] == 0);
ASSERT(m_menuWidths.width[3] == 0);
ASSERT(m_menuWidths.width[5] == 0);
// Only copy the popups if there is a menu loaded
if (hInPlaceMenu != NULL)
{
// Insert our menu popups amongst the container menus
AfxMergeMenus(m_hSharedMenu, hInPlaceMenu,
&m_menuWidths.width[0], 1);
}
}
}
// Finally create the special OLE menu descriptor
m_hOleMenu = ::OleCreateMenuDescriptor(m_hSharedMenu, &m_menuWidths);
}
_AFXCTL_UIACTIVE_INFO::~_AFXCTL_UIACTIVE_INFO()
{
if (m_hSharedMenu != NULL)
::DestroyMenu(m_hSharedMenu);
if (m_hOleMenu != NULL)
VERIFY(::OleDestroyMenuDescriptor(m_hOleMenu) == S_OK);
}
short AFXAPI _AfxShiftState();
void AFXAPI _GetClippingCoordinates(LPCRECT pPosRect, LPCRECT pClipRect,
LPRECT pIntersectRect, LPPOINT pOffsetPoint)
{
int clipLeft = 0;
int clipTop = 0;
if ((pClipRect == NULL) || IsRectEmpty(pClipRect))
{
CopyRect(pIntersectRect, pPosRect);
}
else
{
IntersectRect(pIntersectRect, pPosRect, pClipRect);
clipLeft = pClipRect->left;
clipTop = pClipRect->top;
}
pOffsetPoint->x = min(0, pPosRect->left - clipLeft);
pOffsetPoint->y = min(0, pPosRect->top - clipTop);
}
HRESULT COleControl::OnActivateInPlace(BOOL bUIActivate, LPMSG pMsg)
{
#ifdef _AFXDLL
if (m_bOpen)
{
m_pWndOpenFrame->SetActiveWindow();
SendAdvise(OBJECTCODE_SHOWWINDOW);
return S_OK;
}
#endif
// Initialize pointer to in-place site, if necessary.
if (m_pInPlaceSite == NULL)
{
if (m_pClientSite == NULL)
return E_UNEXPECTED;
if ((GetControlFlags() & windowlessActivate) &&
SUCCEEDED(m_pClientSite->QueryInterface(IID_IOleInPlaceSiteWindowless,
reinterpret_cast<void**>(&m_pInPlaceSiteWndless))))
{
m_bInPlaceSiteWndless = m_bInPlaceSiteEx = TRUE;
}
else if ((GetControlFlags() & noFlickerActivate) &&
SUCCEEDED(m_pClientSite->QueryInterface(IID_IOleInPlaceSiteEx,
reinterpret_cast<void**>(&m_pInPlaceSiteEx))))
{
m_bInPlaceSiteEx = TRUE;
}
else if (SUCCEEDED(m_pClientSite->QueryInterface(IID_IOleInPlaceSite,
reinterpret_cast<void**>(&m_pInPlaceSite))))
{
m_bInPlaceSiteEx = FALSE;
}
else
{
m_pInPlaceSite = NULL;
return E_FAIL;
}
}
ASSERT(m_pInPlaceSite != NULL);
if ((m_bInPlaceActive && !bUIActivate) || m_bUIActive)
{
CWnd* pWndOuter = GetOuterWindow();
HWND hwndParent;
if ((pWndOuter != NULL) &&
SUCCEEDED(m_pInPlaceSite->GetWindow(&hwndParent)) &&
(hwndParent == ::GetParent(pWndOuter->m_hWnd)))
{
::SetWindowPos(pWndOuter->m_hWnd, NULL, 0, 0, 0, 0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
SWP_SHOWWINDOW);
OnSetObjectRects(m_rcPos, NULL);
return S_OK;
}
}
// Check if container allows windowless activation.
if (m_bInPlaceSiteWndless)
{
if (m_pInPlaceSiteWndless->CanWindowlessActivate() != S_OK)
m_bInPlaceSiteWndless = FALSE;
}
HRESULT hr = E_FAIL;
if (m_pInPlaceSite != NULL)
hr = m_pInPlaceSite->CanInPlaceActivate();
if (hr != NOERROR)
{
// Site doesn't allow in-place activation.
return OnOpen(FALSE, pMsg);
}
if (!m_bInPlaceActive)
{
if (m_bInPlaceSiteEx)
{
// flicker-free and/or windowless activation
BOOL bNoRedraw;
m_pInPlaceSiteEx->OnInPlaceActivateEx(&bNoRedraw,
m_bInPlaceSiteWndless ? ACTIVATE_WINDOWLESS : 0);
if (GetControlFlags() & noFlickerActivate)
m_bNoRedraw = bNoRedraw;
}
else
{
// old-style activation
m_pInPlaceSite->OnInPlaceActivate();
}
}
HWND hwndParent = NULL;
if (SUCCEEDED(m_pInPlaceSite->GetWindow(&hwndParent)))
{
CRect rcClip;
m_frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
RELEASE(m_pInPlaceFrame);
RELEASE(m_pInPlaceDoc);
if (SUCCEEDED(m_pInPlaceSite->GetWindowContext(
&m_pInPlaceFrame, &m_pInPlaceDoc,
&m_rcPos, &rcClip, &m_frameInfo)))
{
ASSERT(m_pInPlaceFrame != NULL);
CRect rectClip;
if (!m_bInPlaceSiteWndless)
{
_GetClippingCoordinates(&m_rcPos, &rcClip, rectClip,
&m_ptOffset);
m_bInPlaceActive = CreateControlWindow(hwndParent, m_rcPos,
rectClip);
}
else
{
m_bInPlaceActive = TRUE;
}
if (m_bInPlaceActive)
{
if (bUIActivate)
{
if (m_bInPlaceSiteEx)
{
if (m_pInPlaceSiteEx->RequestUIActivate() != S_OK)
m_pInPlaceSite->OnUIDeactivate(FALSE);
}
BuildSharedMenu();
m_bUIActive = TRUE;
m_pInPlaceSite->OnUIActivate();
m_pInPlaceFrame->SetActiveObject(
&m_xOleInPlaceActiveObject, NULL);
if (m_pInPlaceDoc != NULL)
m_pInPlaceDoc->SetActiveObject(
&m_xOleInPlaceActiveObject, NULL);
if (m_hWnd != NULL)
{
BOOL bHandles = AmbientShowGrabHandles();
BOOL bHatching = AmbientShowHatching();
if (bHandles || bHatching)
CreateTracker(bHandles, bHatching, rcClip);
}
AddFrameLevelUI();
if (bUIActivate != -1 &&
(m_hWnd != NULL) && !IsChild(GetFocus()))
{
SetFocus();
}
}
// Pass thru the window message that caused us to be activated
if ((m_hWnd != NULL || m_bInPlaceSiteWndless) && (pMsg != NULL))
ForwardActivationMsg(pMsg);
// Send appropriate notifications...
SendAdvise(OBJECTCODE_SHOWOBJECT);
return S_OK;
}
}
}
RELEASE(m_pInPlaceFrame);
RELEASE(m_pInPlaceDoc);
return E_FAIL;
}
void COleControl::ForwardActivationMsg(LPMSG pMsg)
{
UINT uMsg = pMsg->message;
LPARAM lParam = pMsg->lParam;
if (m_bInPlaceSiteWndless)
{
// For mouse messages, convert to container window's coordinates
if ((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST))
{
POINT ptNew = pMsg->pt;
HWND hWndContainer = NULL;
if (SUCCEEDED(m_pInPlaceSite->GetWindow(&hWndContainer)))
{
::ScreenToClient(hWndContainer, &ptNew);
lParam = MAKELONG((short)ptNew.x, (short)ptNew.y);
}
}
// Process message on behalf of windowless control
OnWindowlessMessage(uMsg, pMsg->wParam, lParam, NULL);
}
else
{
// For mouse messages, convert to this window's coordinates
if ((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST))
{
POINT ptNew = pMsg->pt;
ScreenToClient(&ptNew);
lParam = MAKELONG((short)ptNew.x, (short)ptNew.y);
}
// Pass the message along to the control's window
SendMessage(uMsg, pMsg->wParam, lParam);
}
}
HMENU COleControl::OnGetInPlaceMenu()
{
// Default: no in-place menu
return NULL;
}
BOOL COleControl::BuildSharedMenu()
{
// This can be called more than once on mouse clicks
if (m_pUIActiveInfo != NULL)
{
ASSERT(m_pUIActiveInfo->m_hSharedMenu != NULL);
return TRUE;
}
HMENU hMenu = m_bUIDead ? NULL : OnGetInPlaceMenu();
TRY
{
m_pUIActiveInfo = new _AFXCTL_UIACTIVE_INFO(hMenu, m_pInPlaceFrame);
}
END_TRY
return (m_pUIActiveInfo != NULL) && (m_pUIActiveInfo->m_hOleMenu != NULL);
}
void COleControl::DestroySharedMenu()
{
ASSERT(m_pUIActiveInfo != NULL);
if (m_pUIActiveInfo == NULL)
return;
HMENU hInPlaceMenu = NULL;
if ((m_pUIActiveInfo->m_hSharedMenu != NULL) &&
((hInPlaceMenu = OnGetInPlaceMenu()) != NULL))
{
// remove our menu popups from the shared menu
AfxUnmergeMenus(m_pUIActiveInfo->m_hSharedMenu, hInPlaceMenu);
// allow container to remove its items from the menu
ASSERT(m_pInPlaceFrame != NULL);
VERIFY(m_pInPlaceFrame->RemoveMenus(m_pUIActiveInfo->m_hSharedMenu) == S_OK);
}
delete m_pUIActiveInfo;
m_pUIActiveInfo = NULL;
}
void COleControl::AddFrameLevelUI()
{
ASSERT(m_pUIActiveInfo != NULL);
if (m_pUIActiveInfo == NULL)
return;
m_pInPlaceFrame->SetMenu(m_pUIActiveInfo->m_hSharedMenu,
m_pUIActiveInfo->m_hOleMenu, m_hWnd);
OnShowToolBars();
}
void COleControl::RemoveFrameLevelUI()
{
ASSERT(m_pUIActiveInfo != NULL);
if (m_pUIActiveInfo == NULL)
return;
OnHideToolBars();
// allow container to remove its items from the menu
ASSERT(m_pInPlaceFrame != NULL);
if (m_pUIActiveInfo->m_hSharedMenu != NULL)
VERIFY(m_pInPlaceFrame->RemoveMenus(m_pUIActiveInfo->m_hSharedMenu) == S_OK);
}
void COleControl::OnShowToolBars()
{
// Default sets border space to empty.
// When overriding, don't call this implementation.
m_pInPlaceFrame->SetBorderSpace(NULL);
}
void COleControl::OnHideToolBars()
{
// Default does nothing
}
/////////////////////////////////////////////////////////////////////////////
// COleControl::XOleInPlaceObject
STDMETHODIMP_(ULONG) COleControl::XOleInPlaceObject::AddRef()
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceObject)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleControl::XOleInPlaceObject::Release()
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceObject)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP COleControl::XOleInPlaceObject::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceObject)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControl::XOleInPlaceObject::GetWindow(HWND* lphwnd)
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceObject)
*lphwnd = pThis->m_bInPlaceActive ? pThis->GetOuterWindow()->m_hWnd : NULL;
return (*lphwnd != NULL) ? S_OK : E_FAIL;
}
STDMETHODIMP COleControl::XOleInPlaceObject::ContextSensitiveHelp(BOOL)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControl::XOleInPlaceObject::InPlaceDeactivate()
{
METHOD_PROLOGUE_EX(COleControl, OleInPlaceObject)
if (!pThis->m_bInPlaceActive)
return S_OK;
pThis->m_bInPlaceActive = FALSE;
if (pThis->m_bUIActive)
UIDeactivate();
// hide the window
if (pThis->m_bInPlaceSiteEx &&
(pThis->GetControlFlags() & noFlickerActivate))
{
// flicker-free deactivation
if (! pThis->m_bInPlaceSiteWndless)
{
pThis->UpdateWindow();
pThis->OnHide();
}
pThis->m_pInPlaceSiteEx->OnInPlaceDeactivateEx(TRUE);
}
else
{
// old-style deactivation
pThis->OnHide();
pThis->m_pInPlaceSite->OnInPlaceDeactivate();
}
return S_OK;
}
STDMETHODIMP COleControl::XOleInPlaceObject::UIDeactivate()
{
METHOD_PROLOGUE_EX(COleControl, OleInPlaceObject)
pThis->m_bPendingUIActivation = FALSE;
if (!pThis->m_bUIActive)
return S_OK;
pThis->DestroyTracker();
pThis->m_bUIActive = FALSE;
if (pThis->m_pInPlaceDoc != NULL)
pThis->m_pInPlaceDoc->SetActiveObject(NULL, NULL);
pThis->m_pInPlaceFrame->SetActiveObject(NULL, NULL);
pThis->RemoveFrameLevelUI();
pThis->DestroySharedMenu();
pThis->m_pInPlaceSite->OnUIDeactivate(FALSE);
return S_OK;
}
STDMETHODIMP COleControl::XOleInPlaceObject::SetObjectRects(LPCRECT lprcPosRect,
LPCRECT lprcClipRect)
{
METHOD_PROLOGUE_EX(COleControl, OleInPlaceObject)
return pThis->OnSetObjectRects(lprcPosRect, lprcClipRect) ?
S_OK :
E_FAIL;
}
BOOL COleControl::OnSetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
ASSERT(lprcPosRect != NULL);
// Remember the position rectangle for later
m_rcPos = *lprcPosRect;
// Calculate complete rectangle including the tracker (if present)
CRect rectPos = m_rcPos;
if (m_bUIActive && m_pRectTracker != NULL)
{
// Save new clipping rectangle (for DestroyTracker)
if (lprcClipRect != NULL)
m_pRectTracker->m_rectClip = *lprcClipRect;
// Adjust tracker rectangle to new dimensions
CRect rectTmp = rectPos;
rectTmp.OffsetRect(-rectTmp.left, -rectTmp.top);
m_pRectTracker->m_rect = rectTmp;
// Adjust the "true" rectangle to include handles/hatching
UINT nHandleSize = m_pRectTracker->m_nHandleSize - 1;
rectPos.InflateRect(nHandleSize, nHandleSize);
}
// Now clip that rectangle as appropriate
CRect rectClip;
_GetClippingCoordinates(rectPos, lprcClipRect, rectClip, &m_ptOffset);
// Move outer window first. then inner window
if (!m_bInPlaceSiteWndless)
{
CWnd* pWndOuter = GetOuterWindow();
pWndOuter->MoveWindow(rectClip);
if (pWndOuter != this)
MoveWindow(m_ptOffset.x, m_ptOffset.y, rectPos.Width(), rectPos.Height());
}
return TRUE;
}
STDMETHODIMP COleControl::XOleInPlaceObject::ReactivateAndUndo()
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
// COleControl::XOleInPlaceActiveObject
STDMETHODIMP_(ULONG) COleControl::XOleInPlaceActiveObject::AddRef()
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceActiveObject)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleControl::XOleInPlaceActiveObject::Release()
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceActiveObject)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceActiveObject)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::GetWindow(HWND* lphwnd)
{
METHOD_PROLOGUE_EX_(COleControl, OleInPlaceActiveObject)
return pThis->m_xOleInPlaceObject.GetWindow(lphwnd);
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::ContextSensitiveHelp(BOOL)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::TranslateAccelerator(
LPMSG lpmsg)
{
METHOD_PROLOGUE_EX(COleControl, OleInPlaceActiveObject)
// Give the control the first chance.
if (pThis->PreTranslateMessage(lpmsg))
return S_OK;
// Give the site a chance.
HRESULT hr = S_FALSE;
if (pThis->m_pControlSite != NULL)
hr = pThis->m_pControlSite->TranslateAccelerator(lpmsg,
(DWORD)_AfxShiftState());
return hr;
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::OnFrameWindowActivate(BOOL)
{
return S_OK;
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::OnDocWindowActivate(
BOOL fActivate)
{
METHOD_PROLOGUE_EX(COleControl, OleInPlaceActiveObject)
if (fActivate && pThis->m_bUIActive)
pThis->AddFrameLevelUI();
else
pThis->OnHideToolBars();
return S_OK;
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::ResizeBorder(
LPCRECT, LPOLEINPLACEUIWINDOW, BOOL)
{
return S_OK;
}
STDMETHODIMP COleControl::XOleInPlaceActiveObject::EnableModeless(BOOL)
{
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// Force any extra compiler-generated code into AFX_INIT_SEG
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif