home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
winfrm.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
60KB
|
2,173 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"
#include <dde.h> // for DDE execute shell requests
#ifdef AFX_CORE4_SEG
#pragma code_seg(AFX_CORE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// CRect for creating windows with the default position/size
const AFX_DATADEF CRect CFrameWnd::rectDefault(
CW_USEDEFAULT, CW_USEDEFAULT,
0 /* 2*CW_USEDEFAULT */, 0 /* 2*CW_USEDEFAULT */);
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd
// register for Windows 95 or Windows NT 3.51
AFX_STATIC UINT _afxMsgMouseWheel =
(((::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 4)) ||
(!(::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 3)))
? ::RegisterWindowMessage(MSH_MOUSEWHEEL) : 0;
BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
//{{AFX_MSG_MAP(CFrameWnd)
ON_WM_INITMENU()
ON_WM_INITMENUPOPUP()
ON_WM_MENUSELECT()
ON_MESSAGE(WM_POPMESSAGESTRING, OnPopMessageString)
ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)
ON_MESSAGE(WM_HELPPROMPTADDR, OnHelpPromptAddr)
ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
ON_WM_ENTERIDLE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_SETFOCUS()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_CLOSE()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_WM_ACTIVATE()
ON_WM_NCACTIVATE()
ON_WM_SYSCOMMAND()
ON_WM_DROPFILES()
ON_WM_QUERYENDSESSION()
ON_WM_ENDSESSION()
ON_WM_SETCURSOR()
ON_WM_ENABLE()
// OLE palette support
ON_WM_QUERYNEWPALETTE()
ON_WM_PALETTECHANGED()
ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel)
// turning on and off standard frame gadgetry
ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateControlBarMenu)
ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateControlBarMenu)
ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_REBAR, OnUpdateControlBarMenu)
ON_COMMAND_EX(ID_VIEW_REBAR, OnBarCheck)
// turning on and off standard mode indicators
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyIndicator)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, OnUpdateKeyIndicator)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, OnUpdateKeyIndicator)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_KANA, OnUpdateKeyIndicator)
// standard help handling
ON_UPDATE_COMMAND_UI(ID_CONTEXT_HELP, OnUpdateContextHelp)
// toolbar "tooltip" notification
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
//}}AFX_MSG_MAP
// message handling for standard DDE commands
ON_MESSAGE(WM_DDE_INITIATE, OnDDEInitiate)
ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute)
ON_MESSAGE(WM_DDE_TERMINATE, OnDDETerminate)
ON_REGISTERED_MESSAGE(_afxMsgMouseWheel, OnRegisteredMouseWheel)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd construction/destruction
CFrameWnd::CFrameWnd()
{
ASSERT(m_hWnd == NULL);
m_nWindow = -1; // unknown window ID
m_bAutoMenuEnable = TRUE; // auto enable on by default
m_lpfnCloseProc = NULL;
m_hMenuDefault = NULL;
m_hAccelTable = NULL;
m_nIDHelp = 0;
m_nIDTracking = 0;
m_nIDLastMessage = 0;
m_pViewActive = NULL;
m_cModalStack = 0; // initialize modality support
m_phWndDisable = NULL;
m_pNotifyHook = NULL;
m_hMenuAlt = NULL;
m_nIdleFlags = 0; // no idle work at start
m_rectBorder.SetRectEmpty();
m_bHelpMode = HELP_INACTIVE; // not in Shift+F1 help mode
m_dwPromptContext = 0;
m_pNextFrameWnd = NULL; // not in list yet
m_bInRecalcLayout = FALSE;
m_pFloatingFrameClass = NULL;
m_nShowDelay = -1; // no delay pending
AddFrameWnd();
}
CFrameWnd::~CFrameWnd()
{
RemoveFrameWnd();
if (m_phWndDisable != NULL)
delete[] (void*)m_phWndDisable;
}
void CFrameWnd::AddFrameWnd()
{
// hook it into the CFrameWnd list
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
pState->m_frameList.AddHead(this);
}
void CFrameWnd::RemoveFrameWnd()
{
// remove this frame window from the list of frame windows
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
pState->m_frameList.Remove(this);
}
/////////////////////////////////////////////////////////////////////////////
// Special processing etc
BOOL CFrameWnd::LoadAccelTable(LPCTSTR lpszResourceName)
{
ASSERT(m_hAccelTable == NULL); // only do once
ASSERT(lpszResourceName != NULL);
HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ACCELERATOR);
m_hAccelTable = ::LoadAccelerators(hInst, lpszResourceName);
return (m_hAccelTable != NULL);
}
HACCEL CFrameWnd::GetDefaultAccelerator()
{
// use document specific accelerator table over m_hAccelTable
HACCEL hAccelTable = m_hAccelTable;
HACCEL hAccel;
CDocument* pDoc = GetActiveDocument();
if (pDoc != NULL && (hAccel = pDoc->GetDefaultAccelerator()) != NULL)
hAccelTable = hAccel;
return hAccelTable;
}
BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg)
{
// check for special cancel modes for combo boxes
if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
AfxCancelModes(pMsg->hwnd); // filter clicks
// allow tooltip messages to be filtered
if (CWnd::PreTranslateMessage(pMsg))
return TRUE;
#ifndef _AFX_NO_OLE_SUPPORT
// allow hook to consume message
if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
return TRUE;
#endif
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
{
// finally, translate the message
HACCEL hAccel = GetDefaultAccelerator();
return hAccel != NULL && ::TranslateAccelerator(m_hWnd, hAccel, pMsg);
}
return FALSE;
}
void CFrameWnd::PostNcDestroy()
{
// default for frame windows is to allocate them on the heap
// the default post-cleanup is to 'delete this'.
// never explicitly call 'delete' on a CFrameWnd, use DestroyWindow instead
delete this;
}
void CFrameWnd::OnPaletteChanged(CWnd* pFocusWnd)
{
CWnd::OnPaletteChanged(pFocusWnd);
#ifndef _AFX_NO_OLE_SUPPORT
if (m_pNotifyHook != NULL)
m_pNotifyHook->OnPaletteChanged(pFocusWnd);
#endif
}
BOOL CFrameWnd::OnQueryNewPalette()
{
#ifndef _AFX_NO_OLE_SUPPORT
if (m_pNotifyHook != NULL && m_pNotifyHook->OnQueryNewPalette())
return TRUE;
#endif
return CWnd::OnQueryNewPalette();
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd support for context sensitive help.
void CFrameWnd::ExitHelpMode()
{
// if not in help mode currently, this is a no-op
if (!m_bHelpMode)
return;
// only post new WM_EXITHELPMODE message if one doesn't already exist
// in the queue.
MSG msg;
if (!::PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE,
PM_REMOVE|PM_NOYIELD))
{
VERIFY(::PostMessage(m_hWnd, WM_EXITHELPMODE, 0, 0));
}
// release capture if this window has it
if (::GetCapture() == m_hWnd)
ReleaseCapture();
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
pFrameWnd->m_bHelpMode = m_bHelpMode = HELP_INACTIVE;
PostMessage(WM_KICKIDLE); // trigger idle update
}
BOOL CFrameWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
if (pFrameWnd->m_bHelpMode)
{
SetCursor(afxData.hcurHelp);
return TRUE;
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
LRESULT CFrameWnd::OnCommandHelp(WPARAM, LPARAM lParam)
{
if (lParam == 0)
{
if (IsTracking())
lParam = HID_BASE_COMMAND+m_nIDTracking;
else
lParam = HID_BASE_RESOURCE+m_nIDHelp;
}
if (lParam != 0)
{
CWinApp* pApp = AfxGetApp();
if (pApp != NULL)
pApp->WinHelp(lParam);
return TRUE;
}
return FALSE;
}
LRESULT CFrameWnd::OnHelpHitTest(WPARAM, LPARAM)
{
if (m_nIDHelp != 0)
return HID_BASE_RESOURCE+m_nIDHelp;
else
return 0;
}
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
// return TRUE if command invocation was attempted
{
HWND hWndCtrl = (HWND)lParam;
UINT nID = LOWORD(wParam);
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL &&
nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP)
{
// route as help
if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
return TRUE;
}
// route as normal command
return CWnd::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd support for modality
BOOL AFXAPI AfxIsDescendant(HWND hWndParent, HWND hWndChild)
// helper for detecting whether child descendent of parent
// (works with owned popups as well)
{
ASSERT(::IsWindow(hWndParent));
ASSERT(::IsWindow(hWndChild));
do
{
if (hWndParent == hWndChild)
return TRUE;
hWndChild = AfxGetParentOwner(hWndChild);
} while (hWndChild != NULL);
return FALSE;
}
void CFrameWnd::BeginModalState()
{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
// allow stacking, but don't do anything
if (++m_cModalStack > 1)
return;
// determine top-level parent, since that is the true parent of any
// modeless windows anyway...
CWnd* pParent = GetTopLevelParent();
// first count all windows that need to be disabled
UINT nCount = 0;
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while (hWnd != NULL)
{
if (::IsWindowEnabled(hWnd) &&
CWnd::FromHandlePermanent(hWnd) != NULL &&
AfxIsDescendant(pParent->m_hWnd, hWnd) &&
::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
{
++nCount;
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
if (nCount == 0)
return;
m_phWndDisable = new HWND[nCount+1];
// disable all windows connected to this frame (and add them to the list)
UINT nIndex = 0;
hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while (hWnd != NULL)
{
if (::IsWindowEnabled(hWnd) &&
CWnd::FromHandlePermanent(hWnd) != NULL &&
AfxIsDescendant(pParent->m_hWnd, hWnd) &&
::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
{
::EnableWindow(hWnd, FALSE);
ASSERT(nIndex < nCount);
m_phWndDisable[nIndex] = hWnd;
++nIndex;
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
// terminate the list with a NULL
ASSERT(nIndex < nCount+1);
m_phWndDisable[nIndex] = NULL;
}
void CFrameWnd::EndModalState()
{
// pop one off the stack (don't undo modalness unless stack is down to zero)
if (m_cModalStack == 0 || --m_cModalStack > 0 || m_phWndDisable == NULL)
return;
// enable all the windows disabled by BeginModalState
ASSERT(m_phWndDisable != NULL);
UINT nIndex = 0;
while (m_phWndDisable[nIndex] != NULL)
{
ASSERT(m_phWndDisable[nIndex] != NULL);
if (::IsWindow(m_phWndDisable[nIndex]))
::EnableWindow(m_phWndDisable[nIndex], TRUE);
++nIndex;
}
delete[] (void*)m_phWndDisable;
m_phWndDisable = NULL;
}
void CFrameWnd::ShowOwnedWindows(BOOL bShow)
{
// walk through all top-level windows
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while (hWnd != NULL)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL && m_hWnd != hWnd && AfxIsDescendant(m_hWnd, hWnd))
{
DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
if (!bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
{
::ShowWindow(hWnd, SW_HIDE);
pWnd->m_nFlags |= WF_TEMPHIDE;
}
else if (bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == 0 &&
(pWnd->m_nFlags & WF_TEMPHIDE))
{
::ShowWindow(hWnd, SW_SHOWNOACTIVATE);
pWnd->m_nFlags &= ~WF_TEMPHIDE;
}
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}
void CFrameWnd::OnEnable(BOOL bEnable)
{
if (bEnable && (m_nFlags & WF_STAYDISABLED))
{
// Work around for MAPI support. This makes sure the main window
// remains disabled even when the mail system is booting.
EnableWindow(FALSE);
::SetFocus(NULL);
return;
}
// only for top-level (and non-owned) windows
if (GetParent() != NULL)
return;
// this causes modal dialogs to be "truly modal"
if (!bEnable && !InModalState())
{
ASSERT((m_nFlags & WF_MODALDISABLE) == 0);
m_nFlags |= WF_MODALDISABLE;
BeginModalState();
}
else if (bEnable && (m_nFlags & WF_MODALDISABLE))
{
m_nFlags &= ~WF_MODALDISABLE;
EndModalState();
// cause normal focus logic to kick in
if (::GetActiveWindow() == m_hWnd)
SendMessage(WM_ACTIVATE, WA_ACTIVE);
}
// force WM_NCACTIVATE because Windows may think it is unecessary
if (bEnable && (m_nFlags & WF_STAYACTIVE))
SendMessage(WM_NCACTIVATE, TRUE);
// force WM_NCACTIVATE for floating windows too
NotifyFloatingWindows(bEnable ? FS_ENABLE : FS_DISABLE);
}
void CFrameWnd::NotifyFloatingWindows(DWORD dwFlags)
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);
// get top level parent frame window first unless this is a child window
CFrameWnd* pParent = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
ASSERT(pParent != NULL);
if (dwFlags & (FS_DEACTIVATE|FS_ACTIVATE))
{
// update parent window activation state
BOOL bActivate = !(dwFlags & FS_DEACTIVATE);
BOOL bEnabled = pParent->IsWindowEnabled();
if (bActivate && bEnabled && pParent != this)
{
// Excel will try to Activate itself when it receives a
// WM_NCACTIVATE so we need to keep it from doing that here.
m_nFlags |= WF_KEEPMINIACTIVE;
pParent->SendMessage(WM_NCACTIVATE, TRUE);
m_nFlags &= ~WF_KEEPMINIACTIVE;
}
else
{
pParent->SendMessage(WM_NCACTIVATE, FALSE);
}
}
// then update the state of all floating windows owned by the parent
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while (hWnd != NULL)
{
if (AfxIsDescendant(pParent->m_hWnd, hWnd))
::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0);
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd second phase creation
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
}
if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;
}
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE0("Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; // save title for later
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE0("Warning: failed to create CFrameWnd.\n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
ASSERT(pContext != NULL);
ASSERT(pContext->m_pNewViewClass != NULL);
// Note: can be a CWnd with PostNcDestroy self cleanup
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
if (pView == NULL)
{
TRACE1("Warning: Dynamic create of view type %hs failed.\n",
pContext->m_pNewViewClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CWnd, pView);
// views are always created with a border!
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0,0,0,0), this, nID, pContext))
{
TRACE0("Warning: could not create view for frame.\n");
return NULL; // can't continue without a view
}
if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
{
// remove the 3d style from the frame, since the view is
// providing it.
// make sure to recalc the non-client area
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
{
// default create client will create a view if asked for it
if (pContext != NULL && pContext->m_pNewViewClass != NULL)
{
if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)
return FALSE;
}
return TRUE;
}
int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
return OnCreateHelper(lpcs, pContext);
}
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if (CWnd::OnCreate(lpcs) == -1)
return -1;
// create special children first
if (!OnCreateClient(lpcs, pContext))
{
TRACE0("Failed to create client pane/view for frame.\n");
return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized
RecalcLayout();
return 0; // create ok
}
LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)
{
ASSERT_VALID_IDR(nIDResource);
HINSTANCE hInst = AfxFindResourceHandle(
MAKEINTRESOURCE(nIDResource), RT_GROUP_ICON);
HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource));
if (hIcon != NULL)
{
CREATESTRUCT cs;
memset(&cs, 0, sizeof(CREATESTRUCT));
cs.style = dwDefaultStyle;
PreCreateWindow(cs);
// will fill lpszClassName with default WNDCLASS name
// ignore instance handle from PreCreateWindow.
WNDCLASS wndcls;
if (cs.lpszClass != NULL &&
GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) &&
wndcls.hIcon != hIcon)
{
// register a very similar WNDCLASS
return AfxRegisterWndClass(wndcls.style,
wndcls.hCursor, wndcls.hbrBackground, hIcon);
}
}
return NULL; // just use the default
}
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
// attempt to create the window
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
LPCTSTR lpszTitle = m_strTitle;
if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
{
return FALSE; // will self destruct on failure normally
}
// save the default menu handle
ASSERT(m_hWnd != NULL);
m_hMenuDefault = ::GetMenu(m_hWnd);
// load accelerator resource
LoadAccelTable(MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) // send initial update
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}
void CFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt)
{
if (hMenuAlt == NULL)
{
// attempt to get default menu from document
CDocument* pDoc = GetActiveDocument();
if (pDoc != NULL)
hMenuAlt = pDoc->GetDefaultMenu();
// use default menu stored in frame if none from document
if (hMenuAlt == NULL)
hMenuAlt = m_hMenuDefault;
}
// finally, set the menu
::SetMenu(m_hWnd, hMenuAlt);
}
void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
{
// if the frame does not have an active view, set to first pane
CView* pView = NULL;
if (GetActiveView() == NULL)
{
CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))
{
pView = (CView*)pWnd;
SetActiveView(pView, FALSE);
}
}
if (bMakeVisible)
{
// send initial update to all views (and other controls) in the frame
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
// give view a chance to save the focus (CFormView needs this)
if (pView != NULL)
pView->OnActivateFrame(WA_INACTIVE, this);
// finally, activate the frame
// (send the default show command unless the main desktop window)
int nCmdShow = -1; // default
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain
pApp->m_nCmdShow = -1; // set to default after first time
}
ActivateFrame(nCmdShow);
if (pView != NULL)
pView->OnActivateView(TRUE, pView, pView);
}
// update frame counts and frame title (may already have been visible)
if (pDoc != NULL)
pDoc->UpdateFrameCounts();
OnUpdateFrameTitle(TRUE);
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd closing down
void CFrameWnd::OnClose()
{
if (m_lpfnCloseProc != NULL && !(*m_lpfnCloseProc)(this))
return;
// Note: only queries the active document
CDocument* pDocument = GetActiveDocument();
if (pDocument != NULL && !pDocument->CanCloseFrame(this))
{
// document can't close right now -- don't close it
return;
}
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
// attempt to save all documents
if (pDocument == NULL && !pApp->SaveAllModified())
return; // don't close it
// hide the application's windows before closing all the documents
pApp->HideApplication();
// close all documents first
pApp->CloseAllDocuments(FALSE);
// don't exit if there are outstanding component objects
if (!AfxOleCanExitApp())
{
// take user out of control of the app
AfxOleSetUserCtrl(FALSE);
// don't destroy the main window and close down just yet
// (there are outstanding component (OLE) objects)
return;
}
// there are cases where destroying the documents may destroy the
// main window of the application.
if (!afxContextIsDLL && pApp->m_pMainWnd == NULL)
{
AfxPostQuitMessage(0);
return;
}
}
// detect the case that this is the last frame on the document and
// shut down with OnCloseDocument instead.
if (pDocument != NULL && pDocument->m_bAutoDelete)
{
BOOL bOtherFrame = FALSE;
POSITION pos = pDocument->GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = pDocument->GetNextView(pos);
ASSERT_VALID(pView);
if (pView->GetParentFrame() != this)
{
bOtherFrame = TRUE;
break;
}
}
if (!bOtherFrame)
{
pDocument->OnCloseDocument();
return;
}
// allow the document to cleanup before the window is destroyed
pDocument->PreCloseFrame(this);
}
// then destroy the window
DestroyWindow();
}
void CFrameWnd::OnDestroy()
{
DestroyDockBars();
// reset menu to default before final shutdown
if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault)
{
::SetMenu(m_hWnd, m_hMenuDefault);
ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault);
}
// Automatically quit when the main window is destroyed.
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
// closing the main application window
::WinHelp(m_hWnd, NULL, HELP_QUIT, 0L);
// will call PostQuitMessage in CWnd::OnNcDestroy
}
CWnd::OnDestroy();
}
void CFrameWnd::RemoveControlBar(CControlBar *pBar)
{
POSITION pos = m_listControlBars.Find(pBar);
if (pos != NULL)
m_listControlBars.RemoveAt(pos);
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd command/message routing
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
// Delegate scroll messages to active view as well
void CFrameWnd::OnHScroll(UINT, UINT, CScrollBar*)
{
CWnd* pActiveView = GetActiveView();
if (pActiveView != NULL)
{
const MSG* pMsg = GetCurrentMessage();
pActiveView->SendMessage(WM_HSCROLL, pMsg->wParam, pMsg->lParam);
}
}
void CFrameWnd::OnVScroll(UINT, UINT, CScrollBar*)
{
CWnd* pActiveView = GetActiveView();
if (pActiveView != NULL)
{
const MSG* pMsg = GetCurrentMessage();
pActiveView->SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam);
}
}
LRESULT CFrameWnd::OnActivateTopLevel(WPARAM wParam, LPARAM lParam)
{
CWnd::OnActivateTopLevel(wParam, lParam);
// exit Shift+F1 help mode on activation changes
ExitHelpMode();
#ifndef _AFX_NO_OLE_SUPPORT
// allow OnFrameWindowActivate to be sent to in-place items
if (m_pNotifyHook != NULL)
{
// activate when active and when not minimized
m_pNotifyHook->OnActivate(
LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam));
}
#endif
// deactivate current active view
if (AfxGetThread()->m_pMainWnd == this)
{
CView* pActiveView = GetActiveView();
if (pActiveView == NULL)
pActiveView = GetActiveFrame()->GetActiveView();
if (pActiveView != NULL)
pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);
}
// force idle processing to update any key state indicators
PostMessage(WM_KICKIDLE);
return 0;
}
void CFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
CWnd::OnActivate(nState, pWndOther, bMinimized);
// get top level frame unless this is a child window
// determine if window should be active or not
CFrameWnd* pTopLevel = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
ASSERT(pTopLevel != NULL);
CWnd* pActive = (nState == WA_INACTIVE ? pWndOther : this);
BOOL bStayActive =
(pTopLevel == pActive ||
(pTopLevel == pActive->GetTopLevelFrame() &&
(pActive == pTopLevel ||
pActive->SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE) != 0)));
pTopLevel->m_nFlags &= ~WF_STAYACTIVE;
if (bStayActive)
pTopLevel->m_nFlags |= WF_STAYACTIVE;
// sync floating windows to the new state
NotifyFloatingWindows(bStayActive ? FS_ACTIVATE : FS_DEACTIVATE);
// get active view (use active frame if no active view)
CView* pActiveView = GetActiveView();
if (pActiveView == NULL)
pActiveView = GetActiveFrame()->GetActiveView();
// when frame gets activated, re-activate current view
if (pActiveView != NULL)
{
if (nState != WA_INACTIVE && !bMinimized)
pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
// always notify the view of frame activations
pActiveView->OnActivateFrame(nState, this);
}
}
BOOL CFrameWnd::OnNcActivate(BOOL bActive)
{
// stay active if WF_STAYACTIVE bit is on
if (m_nFlags & WF_STAYACTIVE)
bActive = TRUE;
// but do not stay active if the window is disabled
if (!IsWindowEnabled())
bActive = FALSE;
// do not call the base class because it will call Default()
// and we may have changed bActive.
return (BOOL)DefWindowProc(WM_NCACTIVATE, bActive, 0L);
}
void CFrameWnd::OnSysCommand(UINT nID, LONG lParam)
{
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
// set status bar as appropriate
UINT nItemID = (nID & 0xFFF0);
// don't interfere with system commands if not in help mode
if (pFrameWnd->m_bHelpMode)
{
switch (nItemID)
{
case SC_SIZE:
case SC_MOVE:
case SC_MINIMIZE:
case SC_MAXIMIZE:
case SC_NEXTWINDOW:
case SC_PREVWINDOW:
case SC_CLOSE:
case SC_RESTORE:
case SC_TASKLIST:
if (!SendMessage(WM_COMMANDHELP, 0,
HID_BASE_COMMAND+ID_COMMAND_FROM_SC(nItemID)))
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
return;
}
}
// call default functionality
CWnd::OnSysCommand(nID, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// default frame processing
// default drop processing will attempt to open the file
void CFrameWnd::OnDropFiles(HDROP hDropInfo)
{
SetActiveWindow(); // activate us first !
UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
CWinApp* pApp = AfxGetApp();
ASSERT(pApp != NULL);
for (UINT iFile = 0; iFile < nFiles; iFile++)
{
TCHAR szFileName[_MAX_PATH];
::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);
pApp->OpenDocumentFile(szFileName);
}
::DragFinish(hDropInfo);
}
// query end session for main frame will attempt to close it all down
BOOL CFrameWnd::OnQueryEndSession()
{
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
return pApp->SaveAllModified();
return TRUE;
}
// when Windows session ends, close all documents
void CFrameWnd::OnEndSession(BOOL bEnding)
{
if (!bEnding)
return;
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
AfxOleSetUserCtrl(TRUE); // keeps from randomly shutting down
pApp->CloseAllDocuments(TRUE);
// allow application to save settings, etc.
pApp->ExitInstance();
}
}
/////////////////////////////////////////////////////////////////////////////
// Support for Shell DDE Execute messages
LRESULT CFrameWnd::OnDDEInitiate(WPARAM wParam, LPARAM lParam)
{
CWinApp* pApp = AfxGetApp();
if (pApp != NULL &&
LOWORD(lParam) != 0 && HIWORD(lParam) != 0 &&
(ATOM)LOWORD(lParam) == pApp->m_atomApp &&
(ATOM)HIWORD(lParam) == pApp->m_atomSystemTopic)
{
// make duplicates of the incoming atoms (really adding a reference)
TCHAR szAtomName[_MAX_PATH];
VERIFY(GlobalGetAtomName(pApp->m_atomApp,
szAtomName, _MAX_PATH - 1) != 0);
VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomApp);
VERIFY(GlobalGetAtomName(pApp->m_atomSystemTopic,
szAtomName, _MAX_PATH - 1) != 0);
VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomSystemTopic);
// send the WM_DDE_ACK (caller will delete duplicate atoms)
::SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
MAKELPARAM(pApp->m_atomApp, pApp->m_atomSystemTopic));
}
return 0L;
}
// always ACK the execute command - even if we do nothing
LRESULT CFrameWnd::OnDDEExecute(WPARAM wParam, LPARAM lParam)
{
// unpack the DDE message
UINT unused;
HGLOBAL hData;
VERIFY(UnpackDDElParam(WM_DDE_EXECUTE, lParam, &unused, (UINT*)&hData));
// get the command string
TCHAR szCommand[_MAX_PATH * 2];
LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData);
lstrcpyn(szCommand, lpsz, _countof(szCommand));
GlobalUnlock(hData);
// acknowledge now - before attempting to execute
::PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
ReuseDDElParam(lParam, WM_DDE_EXECUTE, WM_DDE_ACK,
(UINT)0x8000, (UINT)hData));
// don't execute the command when the window is disabled
if (!IsWindowEnabled())
{
TRACE1("Warning: DDE command '%s' ignored because window is disabled.\n",
szCommand);
return 0;
}
// execute the command
if (!AfxGetApp()->OnDDECommand(szCommand))
TRACE1("Error: failed to execute DDE command '%s'.\n", szCommand);
return 0L;
}
LRESULT CFrameWnd::OnDDETerminate(WPARAM wParam, LPARAM lParam)
{
::PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)m_hWnd, lParam);
return 0L;
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd attributes
CView* CFrameWnd::GetActiveView() const
{
ASSERT(m_pViewActive == NULL ||
m_pViewActive->IsKindOf(RUNTIME_CLASS(CView)));
return m_pViewActive;
}
void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify)
{
#ifdef _DEBUG
if (pViewNew != NULL)
{
ASSERT(IsChild(pViewNew));
ASSERT_KINDOF(CView, pViewNew);
}
#endif //_DEBUG
CView* pViewOld = m_pViewActive;
if (pViewNew == pViewOld)
return; // do not re-activate if SetActiveView called more than once
m_pViewActive = NULL; // no active for the following processing
// deactivate the old one
if (pViewOld != NULL)
pViewOld->OnActivateView(FALSE, pViewNew, pViewOld);
// if the OnActivateView moves the active window,
// that will veto this change
if (m_pViewActive != NULL)
return; // already set
m_pViewActive = pViewNew;
// activate
if (pViewNew != NULL && bNotify)
pViewNew->OnActivateView(TRUE, pViewNew, pViewOld);
}
/////////////////////////////////////////////////////////////////////////////
// Special view swapping/activation
void CFrameWnd::OnSetFocus(CWnd* pOldWnd)
{
if (m_pViewActive != NULL)
m_pViewActive->SetFocus();
else
CWnd::OnSetFocus(pOldWnd);
}
CDocument* CFrameWnd::GetActiveDocument()
{
ASSERT_VALID(this);
CView* pView = GetActiveView();
if (pView != NULL)
return pView->GetDocument();
return NULL;
}
void CFrameWnd::ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL bDelay)
{
ASSERT(pBar != NULL);
CFrameWnd* pParentFrame = pBar->GetDockingFrame();
ASSERT(pParentFrame->GetTopLevelParent() == GetTopLevelParent());
// parent frame of bar must be related
if (bDelay)
{
pBar->DelayShow(bShow);
pParentFrame->DelayRecalcLayout();
}
else
{
pBar->SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
(bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
// call DelayShow to clear any contradictory DelayShow
pBar->DelayShow(bShow);
if (bShow || !pBar->IsFloating())
pParentFrame->RecalcLayout(FALSE);
}
// show or hide the floating frame as appropriate
if (pBar->IsFloating())
{
int nVisCount = pBar->m_pDockBar != NULL ?
pBar->m_pDockBar->GetDockedVisibleCount() : bShow ? 1 : 0;
if (nVisCount == 1 && bShow)
{
pParentFrame->m_nShowDelay = -1;
if (bDelay)
{
pParentFrame->m_nShowDelay = SW_SHOWNA;
pParentFrame->RecalcLayout(FALSE);
}
else
pParentFrame->ShowWindow(SW_SHOWNA);
}
else if (nVisCount == 0)
{
ASSERT(!bShow);
pParentFrame->m_nShowDelay = -1;
if (bDelay)
pParentFrame->m_nShowDelay = SW_HIDE;
else
pParentFrame->ShowWindow(SW_HIDE);
}
else if (!bDelay)
{
pParentFrame->RecalcLayout(FALSE);
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Command prompts
void CFrameWnd::OnInitMenu(CMenu* pMenu)
{
#ifndef _AFX_NO_OLE_SUPPORT
// allow hook to consume message
if (m_pNotifyHook != NULL)
{
#ifdef _AFXDLL
ASSERT(m_pModuleState != NULL);
if (m_pModuleState->m_dwVersion >= 0x423)
#endif
m_pNotifyHook->OnInitMenu(pMenu);
#endif
}
Default();
}
void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)
{
AfxCancelModes(m_hWnd);
if (bSysMenu)
return; // don't support system menu
#ifndef _AFX_NO_OLE_SUPPORT
// allow hook to consume message
if (m_pNotifyHook != NULL)
{
#ifdef _AFXDLL
ASSERT(m_pModuleState != NULL);
if (m_pModuleState->m_dwVersion >= 0x423)
#endif
if (m_pNotifyHook->OnInitMenuPopup(pMenu, nIndex, bSysMenu))
return;
}
#endif
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 (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
state.m_pParentMenu = pMenu; // parent == child for tracking popup
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
{
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);
}
// adjust for menu deletions and additions
UINT nCount = pMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
void CFrameWnd::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
{
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
#ifndef _AFX_NO_OLE_SUPPORT
// allow hook to consume message
if (m_pNotifyHook != NULL)
{
#ifdef _AFXDLL
ASSERT(m_pModuleState != NULL);
if (m_pModuleState->m_dwVersion >= 0x423)
#endif
if (m_pNotifyHook->OnMenuSelect(nItemID, nFlags, hSysMenu))
return;
}
#endif
// set the tracking state (update on idle)
if (nFlags == 0xFFFF)
{
// cancel menu operation (go back to idle now)
m_nFlags &= ~WF_NOPOPMSG;
if (!pFrameWnd->m_bHelpMode)
m_nIDTracking = AFX_IDS_IDLEMESSAGE;
else
m_nIDTracking = AFX_IDS_HELPMODEMESSAGE;
SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
ASSERT(m_nIDTracking == m_nIDLastMessage);
// update right away
CWnd* pWnd = GetMessageBar();
if (pWnd != NULL)
pWnd->UpdateWindow();
}
else
{
if (nItemID == 0 || nFlags & (MF_SEPARATOR|MF_POPUP))
{
// 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;
}
pFrameWnd->m_nFlags |= WF_NOPOPMSG;
}
// 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_KICKIDLE);
}
void CFrameWnd::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 CFrameWnd::OnPopMessageString(WPARAM wParam, LPARAM lParam)
{
if (m_nFlags & WF_NOPOPMSG)
return 0;
return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);
}
LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM lParam)
{
UINT nIDLast = m_nIDLastMessage;
m_nFlags &= ~WF_NOPOPMSG;
CWnd* pMessageBar = GetMessageBar();
if (pMessageBar != 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)
{
// map SC_CLOSE to PREVIEW_CLOSE when in print preview mode
if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc != NULL)
wParam = AFX_IDS_PREVIEW_CLOSE;
// get message associated with the ID indicated by wParam
GetMessageString(wParam, strMessage);
lpsz = strMessage;
}
pMessageBar->SetWindowText(lpsz);
// update owner of the bar in terms of last message selected
CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame();
if (pFrameWnd != NULL)
{
pFrameWnd->m_nIDLastMessage = (UINT)wParam;
pFrameWnd->m_nIDTracking = (UINT)wParam;
}
}
m_nIDLastMessage = (UINT)wParam; // new ID (or 0)
m_nIDTracking = (UINT)wParam; // so F1 on toolbar buttons work
return nIDLast;
}
LRESULT CFrameWnd::OnHelpPromptAddr(WPARAM, LPARAM)
{
return (LRESULT)&m_dwPromptContext;
}
CWnd* CFrameWnd::GetMessageBar()
{
return GetDescendantWindow(AFX_IDW_STATUS_BAR, TRUE);
}
void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho)
{
CWnd::OnEnterIdle(nWhy, pWho);
if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
return;
SetMessageText(m_nIDTracking);
ASSERT(m_nIDTracking == m_nIDLastMessage);
}
void CFrameWnd::SetMessageText(LPCTSTR lpszText)
{
SendMessage(WM_SETMESSAGESTRING, 0, (LPARAM)lpszText);
}
void CFrameWnd::SetMessageText(UINT nID)
{
SendMessage(WM_SETMESSAGESTRING, (WPARAM)nID);
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd standard control bar management
void CFrameWnd::DestroyDockBars()
{
// create a list of all the dock bars
// this is necessary because m_listControlBars will change
// as the dock bars and floating frames are destroyed
CPtrList listDockBars;
POSITION pos = m_listControlBars.GetHeadPosition();
while (pos != NULL)
{
CDockBar* pDockBar = (CDockBar*)m_listControlBars.GetNext(pos);
ASSERT(pDockBar != NULL);
if (pDockBar->IsDockBar())
listDockBars.AddTail(pDockBar);
}
pos = listDockBars.GetHeadPosition();
while (pos != NULL)
{
CDockBar* pDockBar = (CDockBar*)listDockBars.GetNext(pos);
if (pDockBar->m_bFloating)
{
CFrameWnd* pFrameWnd = pDockBar->GetParentFrame();
ASSERT_VALID(pFrameWnd);
pFrameWnd->DestroyWindow();
}
else
pDockBar->DestroyWindow();
}
}
CControlBar* CFrameWnd::GetControlBar(UINT nID)
{
if (nID == 0)
return NULL;
POSITION pos = m_listControlBars.GetHeadPosition();
while (pos != NULL)
{
CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
ASSERT(pBar != NULL);
if (_AfxGetDlgCtrlID(pBar->m_hWnd) == nID)
{
ASSERT_KINDOF(CControlBar, pBar);
return pBar;
}
}
return NULL;
}
void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
{
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR);
CControlBar* pBar = GetControlBar(pCmdUI->m_nID);
if (pBar != NULL)
{
pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
return;
}
pCmdUI->ContinueRouting();
}
BOOL CFrameWnd::OnBarCheck(UINT nID)
{
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR);
CControlBar* pBar = GetControlBar(nID);
if (pBar != NULL)
{
ShowControlBar(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
return TRUE;
}
return FALSE;
}
BOOL CFrameWnd::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
// need to handle both ANSI and UNICODE versions of the message
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
TCHAR szFullText[256];
CString strTipText;
UINT nID = pNMHDR->idFrom;
if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
{
// idFrom is actually the HWND of the tool
nID = _AfxGetDlgCtrlID((HWND)nID);
}
if (nID != 0) // will be zero on a separator
{
// don't handle the message if no string resource found
if (AfxLoadString(nID, szFullText) == 0)
return FALSE;
// this is the command id, not the button index
AfxExtractSubString(strTipText, szFullText, 1, '\n');
}
#ifndef _UNICODE
if (pNMHDR->code == TTN_NEEDTEXTA)
lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText));
else
_mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText));
#else
if (pNMHDR->code == TTN_NEEDTEXTA)
_wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText));
else
lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText));
#endif
*pResult = 0;
// bring the tooltip window above other popup windows
::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
return TRUE; // message was handled
}
/////////////////////////////////////////////////////////////////////////////
// Support for standard status bar
void CFrameWnd::OnUpdateKeyIndicator(CCmdUI* pCmdUI)
{
UINT nVK;
UINT flag = 0x0001;
switch (pCmdUI->m_nID)
{
case ID_INDICATOR_CAPS:
nVK = VK_CAPITAL;
break;
case ID_INDICATOR_NUM:
nVK = VK_NUMLOCK;
break;
case ID_INDICATOR_SCRL:
nVK = VK_SCROLL;
break;
case ID_INDICATOR_KANA:
nVK = VK_KANA;
// WINBUG: Special case for Windows 3.x. The wrong bit was toggled
// in those systems so this must be special cased. This is fixed
// on systems whose version is 4.x or greater.
if (!afxData.bWin4)
flag = 0x8000;
break;
default:
TRACE1("Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X.\n",
pCmdUI->m_nID);
pCmdUI->ContinueRouting();
return; // not for us
}
pCmdUI->Enable(::GetKeyState(nVK) & flag);
// enable static text based on toggled key state
ASSERT(pCmdUI->m_bEnableChanged);
}
void CFrameWnd::OnUpdateContextHelp(CCmdUI* pCmdUI)
{
if (AfxGetMainWnd() == this)
pCmdUI->SetCheck(!!m_bHelpMode);
else
pCmdUI->ContinueRouting();
}
/////////////////////////////////////////////////////////////////////////////
// Setting title of frame window - UISG standard
void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
{
if ((GetStyle() & FWS_ADDTOTITLE) == 0)
return; // leave it alone!
#ifndef _AFX_NO_OLE_SUPPORT
// allow hook to set the title (used for OLE support)
if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
return;
#endif
CDocument* pDocument = GetActiveDocument();
if (bAddToTitle && pDocument != NULL)
UpdateFrameTitleForDocument(pDocument->GetTitle());
else
UpdateFrameTitleForDocument(NULL);
}
void CFrameWnd::UpdateFrameTitleForDocument(LPCTSTR lpszDocName)
{
// copy first part of title loaded at time of frame creation
TCHAR szText[256+_MAX_PATH];
if (GetStyle() & FWS_PREFIXTITLE)
{
szText[0] = '\0'; // start with nothing
// get name of currently active view
if (lpszDocName != NULL)
{
lstrcpy(szText, lpszDocName);
// add current window # if needed
if (m_nWindow > 0)
wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
lstrcat(szText, _T(" - "));
}
lstrcat(szText, m_strTitle);
}
else
{
// get name of currently active view
lstrcpy(szText, m_strTitle);
if (lpszDocName != NULL)
{
lstrcat(szText, _T(" - "));
lstrcat(szText, lpszDocName);
// add current window # if needed
if (m_nWindow > 0)
wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
}
}
// set title if changed, but don't remove completely
// Note: will be excessive for MDI Frame with maximized child
AfxSetWindowText(m_hWnd, szText);
}
/////////////////////////////////////////////////////////////////////////////
void CFrameWnd::OnSetPreviewMode(BOOL bPreview, CPrintPreviewState* pState)
{
// default implementation changes control bars, menu and main pane window
#ifndef _AFX_NO_OLE_SUPPORT
CFrameWnd* pActiveFrame = GetActiveFrame();
ASSERT_VALID(pActiveFrame);
if (bPreview && pActiveFrame->m_pNotifyHook != NULL)
pActiveFrame->m_pNotifyHook->OnDocActivate(FALSE);
#endif
// Set visibility of standard ControlBars (only the first 32)
DWORD dwOldStates = 0;
POSITION pos = m_listControlBars.GetHeadPosition();
while (pos != NULL)
{
CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
ASSERT_VALID(pBar);
UINT nID = _AfxGetDlgCtrlID(pBar->m_hWnd);
if (nID >= AFX_IDW_CONTROLBAR_FIRST && nID <= AFX_IDW_CONTROLBAR_FIRST+31)
{
DWORD dwMask = 1L << (nID - AFX_IDW_CONTROLBAR_FIRST);
if (pBar->IsVisible())
dwOldStates |= dwMask; // save if previously visible
if (!pBar->IsDockBar() || nID != AFX_IDW_DOCKBAR_FLOAT)
ShowControlBar(pBar, (pState->dwStates & dwMask), TRUE);
}
}
pState->dwStates = dwOldStates; // save for restore
if (bPreview)
{
// Entering Print Preview
ASSERT(m_lpfnCloseProc == NULL); // no chaining
m_lpfnCloseProc = pState->lpfnCloseProc;
// show any modeless dialogs, popup windows, float tools, etc
ShowOwnedWindows(FALSE);
// Hide the main pane
HWND hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
ASSERT(hWnd != NULL); // must be one that we are hiding!
::ShowWindow(hWnd, SW_HIDE);
// Get rid of the menu first (will resize the window)
pState->hMenu = ::GetMenu(m_hWnd);
if (pState->hMenu != NULL)
{
// Invalidate before SetMenu since we are going to replace
// the frame's client area anyway
Invalidate();
SetMenu(NULL);
m_nIdleFlags &= ~idleMenu; // avoid any idle menu processing
}
// Save the accelerator table and remove it.
pState->hAccelTable = m_hAccelTable;
m_hAccelTable = NULL;
LoadAccelTable(MAKEINTRESOURCE(AFX_IDR_PREVIEW_ACCEL));
// Make room for the PreviewView by changing AFX_IDW_PANE_FIRST's ID
// to AFX_IDW_PREVIEW_FIRST
if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
if (hWnd != NULL)
_AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_SAVE);
#ifdef _DEBUG
if ((::GetWindowLong(m_hWnd, GWL_STYLE) & (WS_HSCROLL|WS_VSCROLL)) != 0)
TRACE0("Warning: scroll bars in frame windows may cause unusual behaviour.\n");
#endif
}
else
{
// Leaving Preview
m_lpfnCloseProc = NULL;
// shift original AFX_IDW_PANE_FIRST back to its rightful ID
HWND hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_SAVE);
if (hWnd != NULL)
{
HWND hWndTemp = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
if (hWndTemp != NULL)
_AfxSetDlgCtrlID(hWndTemp, AFX_IDW_PANE_SAVE);
_AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_FIRST);
}
// put the menu back in place if it was removed before
if (pState->hMenu != NULL)
{
// Invalidate before SetMenu since we are going to replace
// the frame's client area anyway
Invalidate();
::SetMenu(m_hWnd, pState->hMenu);
}
// recalc layout now, before showing the main pane
#ifndef _AFX_NO_OLE_SUPPORT
if (pActiveFrame->m_pNotifyHook != NULL)
pActiveFrame->m_pNotifyHook->OnDocActivate(TRUE);
#endif
RecalcLayout();
// now show main pane that was hidden
if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
ASSERT(hWnd != NULL);
::ShowWindow(hWnd, SW_SHOW);
// Restore the Accelerator table
m_hAccelTable = pState->hAccelTable;
// show any modeless dialogs, popup windows, float tools, etc
ShowOwnedWindows(TRUE);
}
}
void CFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
{
m_hMenuAlt = hMenuAlt;
m_nIdleFlags |= idleMenu;
}
void CFrameWnd::OnIdleUpdateCmdUI()
{
// update menu if necessary
if (m_nIdleFlags & idleMenu)
OnUpdateFrameMenu(m_hMenuAlt);
// update title if necessary
if (m_nIdleFlags & idleTitle)
OnUpdateFrameTitle(TRUE);
// recalc layout if necessary
if (m_nIdleFlags & idleLayout)
{
RecalcLayout(m_nIdleFlags & idleNotify);
UpdateWindow();
}
// set the current message string if necessary
if (m_nIDTracking != m_nIDLastMessage)
{
SetMessageText(m_nIDTracking);
ASSERT(m_nIDTracking == m_nIDLastMessage);
}
m_nIdleFlags = 0;
}
CFrameWnd* CFrameWnd::GetActiveFrame()
{
// by default, the active frame is the frame itself (MDI is different)
return this;
}
void CFrameWnd::RecalcLayout(BOOL bNotify)
{
if (m_bInRecalcLayout)
return;
m_bInRecalcLayout = TRUE;
// clear idle flags for recalc layout if called elsewhere
if (m_nIdleFlags & idleNotify)
bNotify = TRUE;
m_nIdleFlags &= ~(idleLayout|idleNotify);
#ifndef _AFX_NO_OLE_SUPPORT
// call the layout hook -- OLE support uses this hook
if (bNotify && m_pNotifyHook != NULL)
m_pNotifyHook->OnRecalcLayout();
#endif
// reposition all the child windows (regardless of ID)
if (GetStyle() & FWS_SNAPTOBARS)
{
CRect rect(0, 0, 32767, 32767);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
&rect, &rect, FALSE);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra,
&m_rectBorder, &rect, TRUE);
CalcWindowRect(&rect);
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}
else
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder);
m_bInRecalcLayout = FALSE;
}
// CFrameWnd implementation of OLE border space negotiation
BOOL CFrameWnd::NegotiateBorderSpace(UINT nBorderCmd, LPRECT lpRectBorder)
{
CRect border, request;
switch (nBorderCmd)
{
case borderGet:
ASSERT(lpRectBorder != NULL);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
lpRectBorder);
break;
case borderRequest:
return TRUE;
case borderSet:
if (lpRectBorder == NULL)
{
if (!m_rectBorder.IsRectNull())
{
// releasing all border space -- recalc needed
m_rectBorder.SetRectEmpty();
return TRUE;
}
// original rect is empty & lpRectBorder is NULL, no recalc needed
return FALSE;
}
if (!::EqualRect(m_rectBorder, lpRectBorder))
{
// the rects are different -- recalc needed
m_rectBorder.CopyRect(lpRectBorder);
return TRUE;
}
return FALSE; // no recalc needed
default:
ASSERT(FALSE); // invalid CFrameWnd::BorderCmd
}
return TRUE;
}
void CFrameWnd::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy); // important for MDI Children
if (nType != SIZE_MINIMIZED)
RecalcLayout();
}
BOOL CFrameWnd::OnEraseBkgnd(CDC* pDC)
{
if (m_pViewActive != NULL)
return TRUE; // active view will erase/paint itself
// for view-less frame just use the default background fill
return CWnd::OnEraseBkgnd(pDC);
}
LRESULT CFrameWnd::OnRegisteredMouseWheel(WPARAM wParam, LPARAM lParam)
{
// convert from MSH_MOUSEWHEEL to WM_MOUSEWHEEL
WORD keyState = 0;
keyState |= (::GetKeyState(VK_CONTROL) < 0) ? MK_CONTROL : 0;
keyState |= (::GetKeyState(VK_SHIFT) < 0) ? MK_SHIFT : 0;
LRESULT lResult;
HWND hwFocus = ::GetFocus();
const HWND hwDesktop = ::GetDesktopWindow();
if (hwFocus == NULL)
lResult = SendMessage(WM_MOUSEWHEEL, (wParam << 16) | keyState, lParam);
else
{
do {
lResult = ::SendMessage(hwFocus, WM_MOUSEWHEEL,
(wParam << 16) | keyState, lParam);
hwFocus = ::GetParent(hwFocus);
}
while (lResult == 0 && hwFocus != NULL && hwFocus != hwDesktop);
}
return lResult;
}
void CFrameWnd::ActivateFrame(int nCmdShow)
// nCmdShow is the normal show mode this frame should be in
{
// translate default nCmdShow (-1)
if (nCmdShow == -1)
{
if (!IsWindowVisible())
nCmdShow = SW_SHOWNORMAL;
else if (IsIconic())
nCmdShow = SW_RESTORE;
}
// bring to top before showing
BringToTop(nCmdShow);
if (nCmdShow != -1)
{
// show the window as specified
ShowWindow(nCmdShow);
// and finally, bring to top after showing
BringToTop(nCmdShow);
}
}
void CFrameWnd::BringToTop(int nCmdShow)
{
// place the window on top except for certain nCmdShow
if (nCmdShow != SW_HIDE &&
nCmdShow != SW_MINIMIZE && nCmdShow != SW_SHOWMINNOACTIVE &&
nCmdShow != SW_SHOWNA && nCmdShow != SW_SHOWNOACTIVATE)
{
// if no last active popup, it will return m_hWnd
HWND hWndLastPop = ::GetLastActivePopup(m_hWnd);
::BringWindowToTop(hWndLastPop);
}
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd Diagnostics
#ifdef _DEBUG
void CFrameWnd::AssertValid() const
{
CWnd::AssertValid();
if (m_pViewActive != NULL)
ASSERT_VALID(m_pViewActive);
}
void CFrameWnd::Dump(CDumpContext& dc) const
{
CWnd::Dump(dc);
dc << "m_hAccelTable = " << (UINT)m_hAccelTable;
dc << "\nm_nWindow = " << m_nWindow;
dc << "\nm_nIDHelp = " << m_nIDHelp;
dc << "\nm_nIDTracking = " << m_nIDTracking;
dc << "\nm_nIDLastMessage = " << m_nIDLastMessage;
if (m_pViewActive != NULL)
dc << "\nwith active view: " << m_pViewActive;
else
dc << "\nno active view";
dc << "\n";
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CControlBar segmentation
CFrameWnd* CControlBar::GetDockingFrame() const
{
CFrameWnd* pFrameWnd = GetParentFrame();
if (pFrameWnd == NULL)
pFrameWnd = m_pDockSite;
ASSERT(pFrameWnd != NULL);
ASSERT_KINDOF(CFrameWnd, pFrameWnd);
return pFrameWnd;
}
BOOL CControlBar::IsFloating() const
{
if (IsDockBar())
return ((CDockBar*)this)->m_bFloating;
else
return m_pDockBar != NULL && m_pDockBar->m_bFloating;
}
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
// in this file for IsKindOf library granularity (IsKindOf references these)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
IMPLEMENT_DYNAMIC(CView, CWnd)
IMPLEMENT_DYNAMIC(CControlBar, CWnd)
/////////////////////////////////////////////////////////////////////////////