home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
wincore.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
109KB
|
3,948 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"
#ifndef _AFX_NO_OCC_SUPPORT
#include "occimpl.h"
#endif
#pragma warning(disable:4706)
#define COMPILE_MULTIMON_STUBS
#include <multimon.h>
#pragma warning(default:4706)
#ifdef AFX_CORE1_SEG
#pragma code_seg(AFX_CORE1_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Globals
const UINT CWnd::m_nMsgDragList = ::RegisterWindowMessage(DRAGLISTMSGSTRING);
// CWnds for setting z-order with SetWindowPos's pWndInsertAfter parameter
const AFX_DATADEF CWnd CWnd::wndTop(HWND_TOP);
const AFX_DATADEF CWnd CWnd::wndBottom(HWND_BOTTOM);
const AFX_DATADEF CWnd CWnd::wndTopMost(HWND_TOPMOST);
const AFX_DATADEF CWnd CWnd::wndNoTopMost(HWND_NOTOPMOST);
const TCHAR _afxWnd[] = AFX_WND;
const TCHAR _afxWndControlBar[] = AFX_WNDCONTROLBAR;
const TCHAR _afxWndMDIFrame[] = AFX_WNDMDIFRAME;
const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;
const TCHAR _afxWndOleControl[] = AFX_WNDOLECONTROL;
/////////////////////////////////////////////////////////////////////////////
// CWnd construction
CWnd::CWnd()
{
AFX_ZERO_INIT_OBJECT(CCmdTarget);
}
CWnd::CWnd(HWND hWnd)
{
AFX_ZERO_INIT_OBJECT(CCmdTarget);
m_hWnd = hWnd;
}
// Change a window's style
AFX_STATIC BOOL AFXAPI _AfxModifyStyle(HWND hWnd, int nStyleOffset,
DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
ASSERT(hWnd != NULL);
DWORD dwStyle = ::GetWindowLong(hWnd, nStyleOffset);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE;
::SetWindowLong(hWnd, nStyleOffset, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
}
BOOL PASCAL
CWnd::ModifyStyle(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
return _AfxModifyStyle(hWnd, GWL_STYLE, dwRemove, dwAdd, nFlags);
}
BOOL PASCAL
CWnd::ModifyStyleEx(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
return _AfxModifyStyle(hWnd, GWL_EXSTYLE, dwRemove, dwAdd, nFlags);
}
/////////////////////////////////////////////////////////////////////////////
// Special helpers for certain windows messages
AFX_STATIC void AFXAPI _AfxPreInitDialog(
CWnd* pWnd, LPRECT lpRectOld, DWORD* pdwStyleOld)
{
ASSERT(lpRectOld != NULL);
ASSERT(pdwStyleOld != NULL);
pWnd->GetWindowRect(lpRectOld);
*pdwStyleOld = pWnd->GetStyle();
}
AFX_STATIC void AFXAPI _AfxPostInitDialog(
CWnd* pWnd, const RECT& rectOld, DWORD dwStyleOld)
{
// must be hidden to start with
if (dwStyleOld & WS_VISIBLE)
return;
// must not be visible after WM_INITDIALOG
if (pWnd->GetStyle() & (WS_VISIBLE|WS_CHILD))
return;
// must not move during WM_INITDIALOG
CRect rect;
pWnd->GetWindowRect(rect);
if (rectOld.left != rect.left || rectOld.top != rect.top)
return;
// must be unowned or owner disabled
CWnd* pParent = pWnd->GetWindow(GW_OWNER);
if (pParent != NULL && pParent->IsWindowEnabled())
return;
if (!pWnd->CheckAutoCenter())
return;
// center modal dialog boxes/message boxes
pWnd->CenterWindow();
}
AFX_STATIC void AFXAPI
_AfxHandleActivate(CWnd* pWnd, WPARAM nState, CWnd* pWndOther)
{
ASSERT(pWnd != NULL);
// send WM_ACTIVATETOPLEVEL when top-level parents change
CWnd* pTopLevel;
if (!(pWnd->GetStyle() & WS_CHILD) &&
(pTopLevel = pWnd->GetTopLevelParent()) != pWndOther->GetTopLevelParent())
{
// lParam points to window getting the WM_ACTIVATE message and
// hWndOther from the WM_ACTIVATE.
HWND hWnd2[2];
hWnd2[0] = pWnd->m_hWnd;
hWnd2[1] = pWndOther->GetSafeHwnd();
// send it...
pTopLevel->SendMessage(WM_ACTIVATETOPLEVEL, nState, (LPARAM)&hWnd2[0]);
}
}
AFX_STATIC BOOL AFXAPI
_AfxHandleSetCursor(CWnd* pWnd, UINT nHitTest, UINT nMsg)
{
if (nHitTest == HTERROR &&
(nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN ||
nMsg == WM_RBUTTONDOWN))
{
// activate the last active window if not active
CWnd* pLastActive = pWnd->GetTopLevelParent();
if (pLastActive != NULL)
pLastActive = pLastActive->GetLastActivePopup();
if (pLastActive != NULL &&
pLastActive != CWnd::GetForegroundWindow() &&
pLastActive->IsWindowEnabled())
{
pLastActive->SetForegroundWindow();
return TRUE;
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Official way to send message to a CWnd
LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
WPARAM wParam = 0, LPARAM lParam = 0)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
MSG oldState = pThreadState->m_lastSentMsg; // save for nesting
pThreadState->m_lastSentMsg.hwnd = hWnd;
pThreadState->m_lastSentMsg.message = nMsg;
pThreadState->m_lastSentMsg.wParam = wParam;
pThreadState->m_lastSentMsg.lParam = lParam;
#ifdef _DEBUG
if (afxTraceFlags & traceWinMsg)
_AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg);
#endif
// Catch exceptions thrown outside the scope of a callback
// in debug builds and warn the user.
LRESULT lResult;
TRY
{
#ifndef _AFX_NO_OCC_SUPPORT
// special case for WM_DESTROY
if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
pWnd->m_pCtrlCont->OnUIActivate(NULL);
#endif
// special case for WM_INITDIALOG
CRect rectOld;
DWORD dwStyle = 0;
if (nMsg == WM_INITDIALOG)
_AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
// delegate to object's WindowProc
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
// more special case for WM_INITDIALOG
if (nMsg == WM_INITDIALOG)
_AfxPostInitDialog(pWnd, rectOld, dwStyle);
}
CATCH_ALL(e)
{
lResult = AfxGetThread()->ProcessWndProcException(e, &pThreadState->m_lastSentMsg);
TRACE1("Warning: Uncaught exception in WindowProc (returning %ld).\n",
lResult);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThreadState->m_lastSentMsg = oldState;
return lResult;
}
const MSG* PASCAL CWnd::GetCurrentMessage()
{
// fill in time and position when asked for
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
pThreadState->m_lastSentMsg.time = ::GetMessageTime();
pThreadState->m_lastSentMsg.pt = CPoint(::GetMessagePos());
return &pThreadState->m_lastSentMsg;
}
LRESULT CWnd::Default()
{
// call DefWindowProc with the last message
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
return DefWindowProc(pThreadState->m_lastSentMsg.message,
pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam);
}
/////////////////////////////////////////////////////////////////////////////
// Map from HWND to CWnd*
#include "fixalloc.h"
class CTempWnd : public CWnd
{
DECLARE_DYNCREATE(CTempWnd)
DECLARE_FIXED_ALLOC(CTempWnd);
};
CHandleMap* PASCAL afxMapHWND(BOOL bCreate)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
if (pState->m_pmapHWND == NULL && bCreate)
{
BOOL bEnable = AfxEnableMemoryTracking(FALSE);
#ifndef _AFX_PORTABLE
_PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
#endif
pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd),
offsetof(CWnd, m_hWnd));
#ifndef _AFX_PORTABLE
AfxSetNewHandler(pnhOldHandler);
#endif
AfxEnableMemoryTracking(bEnable);
}
return pState->m_pmapHWND;
}
CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);
#ifndef _AFX_NO_OCC_SUPPORT
pWnd->AttachControlSite(pMap);
#endif
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
return pWnd;
}
CWnd* PASCAL CWnd::FromHandlePermanent(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND();
CWnd* pWnd = NULL;
if (pMap != NULL)
{
// only look in the permanent map - does no allocations
pWnd = (CWnd*)pMap->LookupPermanent(hWnd);
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
}
return pWnd;
}
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL); // only attach once, detach on destroy
ASSERT(FromHandlePermanent(hWndNew) == NULL);
// must not already be in permanent map
if (hWndNew == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist
ASSERT(pMap != NULL);
pMap->SetPermanent(m_hWnd = hWndNew, this);
#ifndef _AFX_NO_OCC_SUPPORT
AttachControlSite(pMap);
#endif
return TRUE;
}
HWND CWnd::Detach()
{
HWND hWnd = m_hWnd;
if (hWnd != NULL)
{
CHandleMap* pMap = afxMapHWND(); // don't create if not exist
if (pMap != NULL)
pMap->RemoveHandle(m_hWnd);
m_hWnd = NULL;
}
#ifndef _AFX_NO_OCC_SUPPORT
m_pCtrlSite = NULL;
#endif
return hWnd;
}
void CWnd::PreSubclassWindow()
{
// no default processing
}
/////////////////////////////////////////////////////////////////////////////
// The WndProc for all CWnd's and derived classes
LRESULT CALLBACK
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// special message which identifies the window as using AfxWndProc
if (nMsg == WM_QUERYAFXWNDPROC)
return 1;
// all other messages route through message map
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
ASSERT(pWnd != NULL);
ASSERT(pWnd->m_hWnd == hWnd);
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
// always indirectly accessed via AfxGetAfxWndProc
WNDPROC AFXAPI AfxGetAfxWndProc()
{
#ifdef _AFXDLL
return AfxGetModuleState()->m_pfnAfxWndProc;
#else
return &AfxWndProc;
#endif
}
/////////////////////////////////////////////////////////////////////////////
// Special WndProcs (activation handling & gray dialogs)
AFX_STATIC_DATA const TCHAR _afxOldWndProc[] = _T("AfxOldWndProc423");
LRESULT CALLBACK
_AfxActivationWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldWndProc = (WNDPROC)::GetProp(hWnd, _afxOldWndProc);
ASSERT(oldWndProc != NULL);
LRESULT lResult = 0;
TRY
{
BOOL bCallDefault = TRUE;
switch (nMsg)
{
case WM_INITDIALOG:
{
DWORD dwStyle;
CRect rectOld;
CWnd* pWnd = CWnd::FromHandle(hWnd);
_AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
bCallDefault = FALSE;
lResult = CallWindowProc(oldWndProc, hWnd, nMsg, wParam, lParam);
_AfxPostInitDialog(pWnd, rectOld, dwStyle);
}
break;
case WM_ACTIVATE:
_AfxHandleActivate(CWnd::FromHandle(hWnd), wParam,
CWnd::FromHandle((HWND)lParam));
break;
case WM_SETCURSOR:
bCallDefault = !_AfxHandleSetCursor(CWnd::FromHandle(hWnd),
(short)LOWORD(lParam), HIWORD(lParam));
break;
case WM_NCDESTROY:
SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
RemoveProp(hWnd, _afxOldWndProc);
GlobalDeleteAtom(GlobalFindAtom(_afxOldWndProc));
break;
}
// call original wndproc for default handling
if (bCallDefault)
lResult = CallWindowProc(oldWndProc, hWnd, nMsg, wParam, lParam);
}
CATCH_ALL(e)
{
// handle exception
MSG msg;
msg.hwnd = hWnd;
msg.message = nMsg;
msg.wParam = wParam;
msg.lParam = lParam;
lResult = AfxGetThread()->ProcessWndProcException(e, &msg);
TRACE1("Warning: Uncaught exception in _AfxActivationWndProc (returning %ld).\n",
lResult);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return lResult;
}
#ifndef _AFX_NO_GRAYDLG_SUPPORT
LRESULT CALLBACK
_AfxGrayBackgroundWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// handle standard gray backgrounds if enabled
_AFX_WIN_STATE* pWinState = _afxWinState;
if (pWinState->m_hDlgBkBrush != NULL &&
(nMsg == WM_CTLCOLORBTN || nMsg == WM_CTLCOLORDLG ||
nMsg == WM_CTLCOLORSTATIC || nMsg == WM_CTLCOLORSCROLLBAR ||
nMsg == WM_CTLCOLORLISTBOX) &&
CWnd::GrayCtlColor((HDC)wParam, (HWND)lParam,
(UINT)(nMsg - WM_CTLCOLORMSGBOX),
pWinState->m_hDlgBkBrush, pWinState->m_crDlgTextClr))
{
return (LRESULT)pWinState->m_hDlgBkBrush;
}
// do standard activation related things as well
return _AfxActivationWndProc(hWnd, nMsg, wParam, lParam);
}
#else //!_AFX_NO_GRAYDLG_SUPPORT
#define _AfxGrayBackgroundWndProc _AfxActivationWndProc
#endif //_AFX_NO_GRAYDLG_SUPPORT
/////////////////////////////////////////////////////////////////////////////
// Window creation hooks
LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (code != HCBT_CREATEWND)
{
// wait for HCBT_CREATEWND just pass others on...
return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
wParam, lParam);
}
ASSERT(lParam != NULL);
LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
ASSERT(lpcs != NULL);
CWnd* pWndInit = pThreadState->m_pWndInit;
BOOL bContextIsDLL = afxContextIsDLL;
if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !bContextIsDLL))
{
// Note: special check to avoid subclassing the IME window
if (_afxDBCS)
{
// check for cheap CS_IME style first...
if (GetClassLong((HWND)wParam, GCL_STYLE) & CS_IME)
goto lCallNextHook;
// get class name of the window that is being created
LPCTSTR pszClassName;
TCHAR szClassName[_countof("ime")+1];
if (HIWORD(lpcs->lpszClass))
{
pszClassName = lpcs->lpszClass;
}
else
{
szClassName[0] = '\0';
GlobalGetAtomName((ATOM)lpcs->lpszClass, szClassName, _countof(szClassName));
pszClassName = szClassName;
}
// a little more expensive to test this way, but necessary...
if (lstrcmpi(pszClassName, _T("ime")) == 0)
goto lCallNextHook;
}
ASSERT(wParam != NULL); // should be non-NULL HWND
HWND hWnd = (HWND)wParam;
WNDPROC oldWndProc;
if (pWndInit != NULL)
{
#ifdef _AFXDLL
AFX_MANAGE_STATE(pWndInit->m_pModuleState);
#endif
// the window should not be in the permanent map at this time
ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL);
// connect the HWND to pWndInit...
pWndInit->Attach(hWnd);
// allow other subclassing to occur first
pWndInit->PreSubclassWindow();
WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
ASSERT(pOldWndProc != NULL);
#ifndef _AFX_NO_CTL3D_SUPPORT
_AFX_CTL3D_STATE* pCtl3dState;
DWORD dwFlags;
if (!afxData.bWin4 && !bContextIsDLL &&
(pCtl3dState = _afxCtl3dState.GetDataNA()) != NULL &&
pCtl3dState->m_pfnSubclassDlgEx != NULL &&
(dwFlags = AfxCallWndProc(pWndInit, hWnd, WM_QUERY3DCONTROLS)) != 0)
{
// was the class registered with AfxWndProc?
WNDPROC afxWndProc = AfxGetAfxWndProc();
BOOL bAfxWndProc = ((WNDPROC)
GetWindowLong(hWnd, GWL_WNDPROC) == afxWndProc);
pCtl3dState->m_pfnSubclassDlgEx(hWnd, dwFlags);
// subclass the window if not already wired to AfxWndProc
if (!bAfxWndProc)
{
// subclass the window with standard AfxWndProc
oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)afxWndProc);
ASSERT(oldWndProc != NULL);
*pOldWndProc = oldWndProc;
}
}
else
#endif
{
// subclass the window with standard AfxWndProc
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)afxWndProc);
ASSERT(oldWndProc != NULL);
if (oldWndProc != afxWndProc)
*pOldWndProc = oldWndProc;
}
pThreadState->m_pWndInit = NULL;
}
else
{
ASSERT(!bContextIsDLL); // should never get here
// subclass the window with the proc which does gray backgrounds
oldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
if (oldWndProc != NULL && GetProp(hWnd, _afxOldWndProc) == NULL)
{
SetProp(hWnd, _afxOldWndProc, oldWndProc);
if ((WNDPROC)GetProp(hWnd, _afxOldWndProc) == oldWndProc)
{
GlobalAddAtom(_afxOldWndProc);
SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)(pThreadState->m_bDlgCreate ?
_AfxGrayBackgroundWndProc : _AfxActivationWndProc));
ASSERT(oldWndProc != NULL);
}
}
}
}
lCallNextHook:
LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
wParam, lParam);
#ifndef _AFXDLL
if (bContextIsDLL)
{
::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
pThreadState->m_hHookOldCbtFilter = NULL;
}
#endif
return lResult;
}
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_pWndInit == pWnd)
return;
if (pThreadState->m_hHookOldCbtFilter == NULL)
{
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
if (pThreadState->m_hHookOldCbtFilter == NULL)
AfxThrowMemoryException();
}
ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);
ASSERT(pWnd != NULL);
ASSERT(pWnd->m_hWnd == NULL); // only do once
ASSERT(pThreadState->m_pWndInit == NULL); // hook not already in progress
pThreadState->m_pWndInit = pWnd;
}
BOOL AFXAPI AfxUnhookWindowCreate()
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
#ifndef _AFXDLL
if (afxContextIsDLL && pThreadState->m_hHookOldCbtFilter != NULL)
{
::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
pThreadState->m_hHookOldCbtFilter = NULL;
}
#endif
if (pThreadState->m_pWndInit != NULL)
{
pThreadState->m_pWndInit = NULL;
return FALSE; // was not successfully hooked
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CWnd creation
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */)
{
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
#ifdef _DEBUG
if (hWnd == NULL)
{
TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
GetLastError());
}
#endif
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
return TRUE;
}
// for child windows
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
// make sure the default window class is registered
VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
// no WNDCLASS provided - use child window default
ASSERT(cs.style & WS_CHILD);
cs.lpszClass = _afxWnd;
}
return TRUE;
}
BOOL CWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext)
{
// can't use for desktop or pop-up windows (use CreateEx instead)
ASSERT(pParentWnd != NULL);
ASSERT((dwStyle & WS_POPUP) == 0);
return CreateEx(0, lpszClassName, lpszWindowName,
dwStyle | WS_CHILD,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext);
}
CWnd::~CWnd()
{
if (m_hWnd != NULL &&
this != (CWnd*)&wndTop && this != (CWnd*)&wndBottom &&
this != (CWnd*)&wndTopMost && this != (CWnd*)&wndNoTopMost)
{
TRACE(_T("Warning: calling DestroyWindow in CWnd::~CWnd; ")
_T("OnDestroy or PostNcDestroy in derived class will not be called.\n"));
DestroyWindow();
}
#ifndef _AFX_NO_OCC_SUPPORT
// cleanup control container,
// including destroying controls
delete m_pCtrlCont;
// cleanup control site
if (m_pCtrlSite != NULL && m_pCtrlSite->m_pWndCtrl == this)
m_pCtrlSite->m_pWndCtrl = NULL;
#endif
}
void CWnd::OnDestroy()
{
#ifndef _AFX_NO_OCC_SUPPORT
// cleanup control container
delete m_pCtrlCont;
m_pCtrlCont = NULL;
#endif
Default();
}
// WM_NCDESTROY is the absolute LAST message sent.
void CWnd::OnNcDestroy()
{
// cleanup main and active windows
CWinThread* pThread = AfxGetThread();
if (pThread != NULL)
{
if (pThread->m_pMainWnd == this)
{
if (!afxContextIsDLL)
{
// shut down current thread if possible
if (pThread != AfxGetApp() || AfxOleCanExitApp())
AfxPostQuitMessage(0);
}
pThread->m_pMainWnd = NULL;
}
if (pThread->m_pActiveWnd == this)
pThread->m_pActiveWnd = NULL;
}
#ifndef _AFX_NO_OLE_SUPPORT
// cleanup OLE drop target interface
if (m_pDropTarget != NULL)
{
m_pDropTarget->Revoke();
m_pDropTarget = NULL;
}
#endif
#ifndef _AFX_NO_OCC_SUPPORT
// cleanup control container
delete m_pCtrlCont;
m_pCtrlCont = NULL;
#endif
// cleanup tooltip support
if (m_nFlags & WF_TOOLTIPS)
{
CToolTipCtrl* pToolTip = AfxGetThreadState()->m_pToolTip;
if (pToolTip->GetSafeHwnd() != NULL)
{
TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
ti.cbSize = sizeof(AFX_OLDTOOLINFO);
ti.uFlags = TTF_IDISHWND;
ti.hwnd = m_hWnd;
ti.uId = (UINT)m_hWnd;
pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&ti);
}
}
// call default, unsubclass, and detach from the map
LONG pfnWndProc = GetWindowLong(m_hWnd, GWL_WNDPROC);
Default();
if (GetWindowLong(m_hWnd, GWL_WNDPROC) == pfnWndProc)
{
WNDPROC pfnSuper = *GetSuperWndProcAddr();
if (pfnSuper != NULL)
SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)pfnSuper);
}
Detach();
ASSERT(m_hWnd == NULL);
// call special post-cleanup routine
PostNcDestroy();
}
void CWnd::PostNcDestroy()
{
// default to nothing
}
void CWnd::OnFinalRelease()
{
if (m_hWnd != NULL)
DestroyWindow(); // will call PostNcDestroy
else
PostNcDestroy();
}
#ifdef _DEBUG
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return; // null (unattached) windows are valid
// check for special wnd??? values
ASSERT(HWND_TOP == NULL); // same as desktop
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
// should be a normal window
ASSERT(::IsWindow(m_hWnd));
// should also be in the permanent or temporary handle map
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CObject* p;
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
}
}
void CWnd::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "\nm_hWnd = " << (UINT)m_hWnd;
if (m_hWnd == NULL || m_hWnd == HWND_BOTTOM ||
m_hWnd == HWND_TOPMOST || m_hWnd == HWND_NOTOPMOST)
{
// not a normal window - nothing more to dump
return;
}
if (!::IsWindow(m_hWnd))
{
// not a valid window
dc << " (illegal HWND)";
return; // don't do anything more
}
CWnd* pWnd = CWnd::FromHandlePermanent(m_hWnd);
if (pWnd != this)
dc << " (Detached or temporary window)";
else
dc << " (permanent window)";
// dump out window specific statistics
TCHAR szBuf [64];
if (!::SendMessage(m_hWnd, WM_QUERYAFXWNDPROC, 0, 0) && pWnd == this)
GetWindowText(szBuf, _countof(szBuf));
else
::DefWindowProc(m_hWnd, WM_GETTEXT, _countof(szBuf), (LPARAM)&szBuf[0]);
dc << "\ncaption = \"" << szBuf << "\"";
::GetClassName(m_hWnd, szBuf, _countof(szBuf));
dc << "\nclass name = \"" << szBuf << "\"";
CRect rect;
GetWindowRect(&rect);
dc << "\nrect = " << rect;
dc << "\nparent CWnd* = " << (void*)GetParent();
dc << "\nstyle = " << (void*)::GetWindowLong(m_hWnd, GWL_STYLE);
if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_CHILD)
dc << "\nid = " << _AfxGetDlgCtrlID(m_hWnd);
dc << "\n";
}
#endif
BOOL CWnd::DestroyWindow()
{
if (m_hWnd == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
#ifdef _DEBUG
HWND hWndOrig = m_hWnd;
#endif
#ifdef _AFX_NO_OCC_SUPPORT
BOOL bResult = ::DestroyWindow(m_hWnd);
#else //_AFX_NO_OCC_SUPPORT
BOOL bResult;
if (m_pCtrlSite == NULL)
bResult = ::DestroyWindow(m_hWnd);
else
bResult = m_pCtrlSite->DestroyControl();
#endif //_AFX_NO_OCC_SUPPORT
// Note that 'this' may have been deleted at this point,
// (but only if pWnd != NULL)
if (pWnd != NULL)
{
// Should have been detached by OnNcDestroy
#ifdef _DEBUG
ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);
#endif
}
else
{
#ifdef _DEBUG
ASSERT(m_hWnd == hWndOrig);
#endif
// Detach after DestroyWindow called just in case
Detach();
}
return bResult;
}
/////////////////////////////////////////////////////////////////////////////
// Default CWnd implementation
LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (m_pfnSuper != NULL)
return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);
WNDPROC pfnWndProc;
if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);
else
return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
}
WNDPROC* CWnd::GetSuperWndProcAddr()
{
// Note: it is no longer necessary to override GetSuperWndProcAddr
// for each control class with a different WNDCLASS.
// This implementation now uses instance data, such that the previous
// WNDPROC can be anything.
return &m_pfnSuper;
}
BOOL CWnd::PreTranslateMessage(MSG* pMsg)
{
// handle tooltip messages (some messages cancel, some may cause it to popup)
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
if (pModuleState->m_pfnFilterToolTipMessage != NULL)
(*pModuleState->m_pfnFilterToolTipMessage)(pMsg, this);
// no default processing
return FALSE;
}
void PASCAL CWnd::CancelToolTips(BOOL bKeys)
{
// check for active tooltip
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
CToolTipCtrl* pToolTip = pThreadState->m_pToolTip;
if (pToolTip->GetSafeHwnd() != NULL)
pToolTip->SendMessage(TTM_ACTIVATE, FALSE);
// check for active control bar fly-by status
CControlBar* pLastStatus = pThreadState->m_pLastStatus;
if (bKeys && pLastStatus != NULL && GetKeyState(VK_LBUTTON) >= 0)
pLastStatus->SetStatusText(-1);
}
int CWnd::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
// find child window which hits the point
// (don't use WindowFromPoint, because it ignores disabled windows)
HWND hWndChild = _AfxChildWindowFromPoint(m_hWnd, point);
if (hWndChild != NULL)
{
// return positive hit if control ID isn't -1
int nHit = _AfxGetDlgCtrlID(hWndChild);
// hits against child windows always center the tip
if (pTI != NULL && pTI->cbSize >= sizeof(AFX_OLDTOOLINFO))
{
// setup the TOOLINFO structure
pTI->hwnd = m_hWnd;
pTI->uId = (UINT)hWndChild;
pTI->uFlags |= TTF_IDISHWND;
pTI->lpszText = LPSTR_TEXTCALLBACK;
// set TTF_NOTBUTTON and TTF_CENTERTIP if it isn't a button
if (!(::SendMessage(hWndChild, WM_GETDLGCODE, 0, 0) & DLGC_BUTTON))
pTI->uFlags |= TTF_NOTBUTTON|TTF_CENTERTIP;
}
return nHit;
}
return -1; // not found
}
void CWnd::GetWindowText(CString& rString) const
{
ASSERT(::IsWindow(m_hWnd));
#ifndef _AFX_NO_OCC_SUPPORT
if (m_pCtrlSite == NULL)
{
#endif
int nLen = ::GetWindowTextLength(m_hWnd);
::GetWindowText(m_hWnd, rString.GetBufferSetLength(nLen), nLen+1);
rString.ReleaseBuffer();
#ifndef _AFX_NO_OCC_SUPPORT
}
else
{
m_pCtrlSite->GetWindowText(rString);
}
#endif
}
int CWnd::GetDlgItemText(int nID, CString& rString) const
{
ASSERT(::IsWindow(m_hWnd));
rString = &afxChNil; // empty without deallocating
#ifndef _AFX_NO_OCC_SUPPORT
if (m_pCtrlCont == NULL)
{
#endif
HWND hWnd = ::GetDlgItem(m_hWnd, nID);
if (hWnd != NULL)
{
int nLen = ::GetWindowTextLength(hWnd);
::GetWindowText(hWnd, rString.GetBufferSetLength(nLen), nLen+1);
rString.ReleaseBuffer();
}
#ifndef _AFX_NO_OCC_SUPPORT
}
else
{
CWnd* pWnd = GetDlgItem(nID);
if (pWnd != NULL)
pWnd->GetWindowText(rString);
}
#endif
return rString.GetLength();
}
BOOL CWnd::GetWindowPlacement(WINDOWPLACEMENT* lpwndpl) const
{
ASSERT(::IsWindow(m_hWnd));
lpwndpl->length = sizeof(WINDOWPLACEMENT);
return ::GetWindowPlacement(m_hWnd, lpwndpl);
}
BOOL CWnd::SetWindowPlacement(const WINDOWPLACEMENT* lpwndpl)
{
ASSERT(::IsWindow(m_hWnd));
((WINDOWPLACEMENT*)lpwndpl)->length = sizeof(WINDOWPLACEMENT);
return ::SetWindowPlacement(m_hWnd, lpwndpl);
}
/////////////////////////////////////////////////////////////////////////////
// CWnd will delegate owner draw messages to self drawing controls
// Drawing: for all 4 control types
void CWnd::OnDrawItem(int /*nIDCtl*/, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (lpDrawItemStruct->CtlType == ODT_MENU)
{
CMenu* pMenu = CMenu::FromHandlePermanent(
(HMENU)lpDrawItemStruct->hwndItem);
if (pMenu != NULL)
{
pMenu->DrawItem(lpDrawItemStruct);
return; // eat it
}
}
else
{
// reflect notification to child window control
if (ReflectLastMsg(lpDrawItemStruct->hwndItem))
return; // eat it
}
// not handled - do default
Default();
}
// Drawing: for all 4 control types
int CWnd::OnCompareItem(int /*nIDCtl*/, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{
// reflect notification to child window control
LRESULT lResult;
if (ReflectLastMsg(lpCompareItemStruct->hwndItem, &lResult))
return (int)lResult; // eat it
// not handled - do default
return (int)Default();
}
void CWnd::OnDeleteItem(int /*nIDCtl*/, LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
// reflect notification to child window control
if (ReflectLastMsg(lpDeleteItemStruct->hwndItem))
return; // eat it
// not handled - do default
Default();
}
int CWnd::OnCharToItem(UINT, CListBox* pWnd, UINT)
{
if (pWnd != NULL)
{
LRESULT lResult;
if (pWnd->SendChildNotifyLastMsg(&lResult))
return (int)lResult; // eat it
}
// not handled - do default
return (int)Default();
}
int CWnd::OnVKeyToItem(UINT, CListBox* pWnd, UINT)
{
if (pWnd != NULL)
{
LRESULT lResult;
if (pWnd->SendChildNotifyLastMsg(&lResult))
return (int)lResult; // eat it
}
// not handled - do default
return (int)Default();
}
/////////////////////////////////////////////////////////////////////////////
// Self drawing menus are a little trickier
BOOL CMenu::TrackPopupMenu(UINT nFlags, int x, int y,
CWnd* pWnd, LPCRECT lpRect)
{
ASSERT(m_hMenu != NULL);
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
HWND hWndOld = pThreadState->m_hTrackingWindow;
HMENU hMenuOld = pThreadState->m_hTrackingMenu;
pThreadState->m_hTrackingWindow = pWnd->GetSafeHwnd();
pThreadState->m_hTrackingMenu = m_hMenu;
BOOL bOK = ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0,
pThreadState->m_hTrackingWindow, lpRect);
pThreadState->m_hTrackingWindow = hWndOld;
pThreadState->m_hTrackingMenu = hMenuOld;
return bOK;
}
AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ASSERT_VALID(pMenu);
// walk through all items, looking for ID match
UINT nItems = pMenu->GetMenuItemCount();
for (int iItem = 0; iItem < (int)nItems; iItem++)
{
CMenu* pPopup = pMenu->GetSubMenu(iItem);
if (pPopup != NULL)
{
// recurse to child popup
pPopup = _AfxFindPopupMenuFromID(pPopup, nID);
// check popups on this popup
if (pPopup != NULL)
return pPopup;
}
else if (pMenu->GetMenuItemID(iItem) == nID)
{
// it is a normal item inside our popup
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
}
// not found
return NULL;
}
// Measure item implementation relies on unique control/menu IDs
void CWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (lpMeasureItemStruct->CtlType == ODT_MENU)
{
ASSERT(lpMeasureItemStruct->CtlID == 0);
CMenu* pMenu;
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_hTrackingWindow == m_hWnd)
{
// start from popup
pMenu = CMenu::FromHandle(pThreadState->m_hTrackingMenu);
}
else
{
// start from menubar
pMenu = GetMenu();
}
pMenu = _AfxFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if (pMenu != NULL)
pMenu->MeasureItem(lpMeasureItemStruct);
else
TRACE1("Warning: unknown WM_MEASUREITEM for menu item 0x%04X.\n",
lpMeasureItemStruct->itemID);
}
else
{
CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
if (pChild != NULL && pChild->SendChildNotifyLastMsg())
return; // eaten by child
}
// not handled - do default
Default();
}
/////////////////////////////////////////////////////////////////////////////
// Additional helpers for WNDCLASS init
// like RegisterClass, except will automatically call UnregisterClass
BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
WNDCLASS wndcls;
if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
&wndcls))
{
// class already registered
return TRUE;
}
if (!::RegisterClass(lpWndClass))
{
TRACE1("Can't register window class named %s\n",
lpWndClass->lpszClassName);
return FALSE;
}
if (afxContextIsDLL)
{
AfxLockGlobals(CRIT_REGCLASSLIST);
TRY
{
// class registered successfully, add to registered list
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList;
// the buffer is of fixed size -- ensure that it does not overflow
ASSERT(lstrlen(lpszUnregisterList) + 1 +
lstrlen(lpWndClass->lpszClassName) + 1 <
_countof(pModuleState->m_szUnregisterList));
// append classname + newline to m_szUnregisterList
lstrcat(lpszUnregisterList, lpWndClass->lpszClassName);
TCHAR szTemp[2];
szTemp[0] = '\n';
szTemp[1] = '\0';
lstrcat(lpszUnregisterList, szTemp);
}
CATCH_ALL(e)
{
AfxUnlockGlobals(CRIT_REGCLASSLIST);
THROW_LAST();
// Note: DELETE_EXCEPTION not required.
}
END_CATCH_ALL
AfxUnlockGlobals(CRIT_REGCLASSLIST);
}
return TRUE;
}
LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,
HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)
{
// Returns a temporary string name for the class
// Save in a CString if you want to use it for a long time
LPTSTR lpszName = AfxGetThreadState()->m_szTempClassName;
// generate a synthetic name for this class
HINSTANCE hInst = AfxGetInstanceHandle();
if (hCursor == NULL && hbrBackground == NULL && hIcon == NULL)
wsprintf(lpszName, _T("Afx:%x:%x"), (UINT)hInst, nClassStyle);
else
wsprintf(lpszName, _T("Afx:%x:%x:%x:%x:%x"), (UINT)hInst, nClassStyle,
(UINT)hCursor, (UINT)hbrBackground, (UINT)hIcon);
// see if the class already exists
WNDCLASS wndcls;
if (::GetClassInfo(hInst, lpszName, &wndcls))
{
// already registered, assert everything is good
ASSERT(wndcls.style == nClassStyle);
// NOTE: We have to trust that the hIcon, hbrBackground, and the
// hCursor are semantically the same, because sometimes Windows does
// some internal translation or copying of those handles before
// storing them in the internal WNDCLASS retrieved by GetClassInfo.
return lpszName;
}
// otherwise we need to register a new class
wndcls.style = nClassStyle;
wndcls.lpfnWndProc = DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = hIcon;
wndcls.hCursor = hCursor;
wndcls.hbrBackground = hbrBackground;
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = lpszName;
if (!AfxRegisterClass(&wndcls))
AfxThrowResourceException();
// return thread-local pointer
return lpszName;
}
struct AFX_CTLCOLOR
{
HWND hWnd;
HDC hDC;
UINT nCtlType;
};
LRESULT CWnd::OnNTCtlColor(WPARAM wParam, LPARAM lParam)
{
// fill in special struct for compatiblity with 16-bit WM_CTLCOLOR
AFX_CTLCOLOR ctl;
ctl.hDC = (HDC)wParam;
ctl.hWnd = (HWND)lParam;
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
ctl.nCtlType = pThreadState->m_lastSentMsg.message - WM_CTLCOLORMSGBOX;
ASSERT(ctl.nCtlType >= CTLCOLOR_MSGBOX);
ASSERT(ctl.nCtlType <= CTLCOLOR_STATIC);
// Note: We call the virtual WindowProc for this window directly,
// instead of calling AfxCallWindowProc, so that Default()
// will still work (it will call the Default window proc with
// the original Win32 WM_CTLCOLOR message).
return WindowProc(WM_CTLCOLOR, 0, (LPARAM)&ctl);
}
/////////////////////////////////////////////////////////////////////////////
// CWnd extensions for help support
void CWnd::WinHelp(DWORD dwData, UINT nCmd)
{
CWinApp* pApp = AfxGetApp();
ASSERT_VALID(pApp);
ASSERT(pApp->m_pszHelpFilePath != NULL);
CWaitCursor wait;
if (IsFrameWnd())
{
// CFrameWnd windows should be allowed to exit help mode first
CFrameWnd* pFrameWnd = (CFrameWnd*)this;
pFrameWnd->ExitHelpMode();
}
// cancel any tracking modes
SendMessage(WM_CANCELMODE);
SendMessageToDescendants(WM_CANCELMODE, 0, 0, TRUE, TRUE);
// need to use top level parent (for the case where m_hWnd is in DLL)
CWnd* pWnd = GetTopLevelParent();
pWnd->SendMessage(WM_CANCELMODE);
pWnd->SendMessageToDescendants(WM_CANCELMODE, 0, 0, TRUE, TRUE);
// attempt to cancel capture
HWND hWndCapture = ::GetCapture();
if (hWndCapture != NULL)
::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);
TRACE3("WinHelp: pszHelpFile = '%s', dwData: $%lx, fuCommand: %d.\n",
pApp->m_pszHelpFilePath, dwData, nCmd);
// finally, run the Windows Help engine
if (!::WinHelp(pWnd->m_hWnd, pApp->m_pszHelpFilePath, nCmd, dwData))
AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP);
}
/////////////////////////////////////////////////////////////////////////////
// Message table implementation
BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
ON_MESSAGE(WM_CTLCOLORSTATIC, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLOREDIT, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORBTN, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORLISTBOX, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORDLG, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORMSGBOX, OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORSCROLLBAR, OnNTCtlColor)
//{{AFX_MSG_MAP(CWnd)
ON_WM_DRAWITEM()
ON_WM_MEASUREITEM()
ON_WM_CTLCOLOR()
ON_WM_COMPAREITEM()
ON_WM_ENTERIDLE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_DELETEITEM()
ON_WM_CHARTOITEM()
ON_WM_VKEYTOITEM()
ON_WM_NCDESTROY()
ON_WM_PARENTNOTIFY()
ON_WM_SYSCOLORCHANGE()
ON_WM_DEVMODECHANGE()
ON_WM_HELPINFO()
ON_WM_SETTINGCHANGE()
//}}AFX_MSG_MAP
#ifndef _AFX_NO_OCC_SUPPORT
ON_WM_DESTROY()
#endif
ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel)
ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange)
ON_REGISTERED_MESSAGE(CWnd::m_nMsgDragList, OnDragList)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Routines for fast search of message maps
const AFX_MSGMAP_ENTRY* AFXAPI
AfxFindMessageEntry(const AFX_MSGMAP_ENTRY* lpEntry,
UINT nMsg, UINT nCode, UINT nID)
{
#if defined(_M_IX86) && !defined(_AFX_PORTABLE)
// 32-bit Intel 386/486 version.
ASSERT(offsetof(AFX_MSGMAP_ENTRY, nMessage) == 0);
ASSERT(offsetof(AFX_MSGMAP_ENTRY, nCode) == 4);
ASSERT(offsetof(AFX_MSGMAP_ENTRY, nID) == 8);
ASSERT(offsetof(AFX_MSGMAP_ENTRY, nLastID) == 12);
ASSERT(offsetof(AFX_MSGMAP_ENTRY, nSig) == 16);
_asm
{
MOV EBX,lpEntry
MOV EAX,nMsg
MOV EDX,nCode
MOV ECX,nID
__loop:
CMP DWORD PTR [EBX+16],0 ; nSig (0 => end)
JZ __failed
CMP EAX,DWORD PTR [EBX] ; nMessage
JE __found_message
__next:
ADD EBX,SIZE AFX_MSGMAP_ENTRY
JMP short __loop
__found_message:
CMP EDX,DWORD PTR [EBX+4] ; nCode
JNE __next
// message and code good so far
// check the ID
CMP ECX,DWORD PTR [EBX+8] ; nID
JB __next
CMP ECX,DWORD PTR [EBX+12] ; nLastID
JA __next
// found a match
MOV lpEntry,EBX ; return EBX
JMP short __end
__failed:
XOR EAX,EAX ; return NULL
MOV lpEntry,EAX
__end:
}
return lpEntry;
#else // _AFX_PORTABLE
// C version of search routine
while (lpEntry->nSig != AfxSig_end)
{
if (lpEntry->nMessage == nMsg && lpEntry->nCode == nCode &&
nID >= lpEntry->nID && nID <= lpEntry->nLastID)
{
return lpEntry;
}
lpEntry++;
}
return NULL; // not found
#endif // _AFX_PORTABLE
}
/////////////////////////////////////////////////////////////////////////////
// Cache of most recently sent messages
#ifndef iHashMax
// iHashMax must be a power of two
#define iHashMax 512
#endif
struct AFX_MSG_CACHE
{
UINT nMsg;
const AFX_MSGMAP_ENTRY* lpEntry;
const AFX_MSGMAP* pMessageMap;
};
AFX_MSG_CACHE _afxMsgCache[iHashMax];
void AFXAPI AfxResetMsgCache()
{
memset(_afxMsgCache, 0, sizeof(_afxMsgCache));
}
/////////////////////////////////////////////////////////////////////////////
// main WindowProc implementation
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// OnWndMsg does most of the work, except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LRESULT lResult = 0;
// special case for commands
if (message == WM_COMMAND)
{
if (OnCommand(wParam, lParam))
{
lResult = 1;
goto LReturnTrue;
}
return FALSE;
}
// special case for notifies
if (message == WM_NOTIFY)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
goto LReturnTrue;
return FALSE;
}
// special case for activation
if (message == WM_ACTIVATE)
_AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam));
// special case for set cursor HTERROR
if (message == WM_SETCURSOR &&
_AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam)))
{
lResult = 1;
goto LReturnTrue;
}
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1);
AfxLockGlobals(CRIT_WINMSGCACHE);
AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
const AFX_MSGMAP_ENTRY* lpEntry;
if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
{
// cache hit
lpEntry = pMsgCache->lpEntry;
AfxUnlockGlobals(CRIT_WINMSGCACHE);
if (lpEntry == NULL)
return FALSE;
// cache hit, and it needs to be handled
if (message < 0xC000)
goto LDispatch;
else
goto LDispatchRegistered;
}
else
{
// not in cache, look for it
pMsgCache->nMsg = message;
pMsgCache->pMessageMap = pMessageMap;
#ifdef _AFXDLL
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
#else
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
#endif
{
// Note: catch not so common but fatal mistake!!
// BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
#ifdef _AFXDLL
ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
#else
ASSERT(pMessageMap != pMessageMap->pBaseMap);
#endif
if (message < 0xC000)
{
// constant window message
if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
message, 0, 0)) != NULL)
{
pMsgCache->lpEntry = lpEntry;
AfxUnlockGlobals(CRIT_WINMSGCACHE);
goto LDispatch;
}
}
else
{
// registered windows message
lpEntry = pMessageMap->lpEntries;
while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
{
UINT* pnID = (UINT*)(lpEntry->nSig);
ASSERT(*pnID >= 0xC000 || *pnID == 0);
// must be successfully registered
if (*pnID == message)
{
pMsgCache->lpEntry = lpEntry;
AfxUnlockGlobals(CRIT_WINMSGCACHE);
goto LDispatchRegistered;
}
lpEntry++; // keep looking past this one
}
}
}
pMsgCache->lpEntry = NULL;
AfxUnlockGlobals(CRIT_WINMSGCACHE);
return FALSE;
}
ASSERT(FALSE); // not reached
LDispatch:
ASSERT(message < 0xC000);
union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn;
// if we've got WM_SETTINGCHANGE / WM_WININICHANGE, we need to
// decide if we're going to call OnWinIniChange() or OnSettingChange()
int nSig;
nSig = lpEntry->nSig;
if (lpEntry->nID == WM_SETTINGCHANGE)
{
DWORD dwVersion = GetVersion();
if (LOBYTE(LOWORD(dwVersion)) >= 4)
nSig = AfxSig_vws;
else
nSig = AfxSig_vs;
}
switch (nSig)
{
default:
ASSERT(FALSE);
break;
case AfxSig_bD:
lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
break;
case AfxSig_bb: // AfxSig_bb, AfxSig_bw, AfxSig_bh
lResult = (this->*mmf.pfn_bb)((BOOL)wParam);
break;
case AfxSig_bWww: // really AfxSig_bWiw
lResult = (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
(short)LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_bWCDS:
lResult = (this->*mmf.pfn_bWCDS)(CWnd::FromHandle((HWND)wParam),
(COPYDATASTRUCT*)lParam);
break;
case AfxSig_bHELPINFO:
lResult = (this->*mmf.pfn_bHELPINFO)((HELPINFO*)lParam);
break;
case AfxSig_hDWw:
{
// special case for OnCtlColor to avoid too many temporary objects
ASSERT(message == WM_CTLCOLOR);
AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam;
CDC dcTemp; dcTemp.m_hDC = pCtl->hDC;
CWnd wndTemp; wndTemp.m_hWnd = pCtl->hWnd;
UINT nCtlType = pCtl->nCtlType;
// if not coming from a permanent window, use stack temporary
CWnd* pWnd = CWnd::FromHandlePermanent(wndTemp.m_hWnd);
if (pWnd == NULL)
{
#ifndef _AFX_NO_OCC_SUPPORT
// determine the site of the OLE control if it is one
COleControlSite* pSite;
if (m_pCtrlCont != NULL && (pSite = (COleControlSite*)
m_pCtrlCont->m_siteMap.GetValueAt(wndTemp.m_hWnd)) != NULL)
{
wndTemp.m_pCtrlSite = pSite;
}
#endif
pWnd = &wndTemp;
}
HBRUSH hbr = (this->*mmf.pfn_hDWw)(&dcTemp, pWnd, nCtlType);
// fast detach of temporary objects
dcTemp.m_hDC = NULL;
wndTemp.m_hWnd = NULL;
lResult = (LRESULT)hbr;
}
break;
case AfxSig_hDw:
{
// special case for CtlColor to avoid too many temporary objects
ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam;
CDC dcTemp; dcTemp.m_hDC = pCtl->hDC;
UINT nCtlType = pCtl->nCtlType;
HBRUSH hbr = (this->*mmf.pfn_hDw)(&dcTemp, nCtlType);
// fast detach of temporary objects
dcTemp.m_hDC = NULL;
lResult = (LRESULT)hbr;
}
break;
case AfxSig_iwWw:
lResult = (this->*mmf.pfn_iwWw)(LOWORD(wParam),
CWnd::FromHandle((HWND)lParam), HIWORD(wParam));
break;
case AfxSig_iww:
lResult = (this->*mmf.pfn_iww)(LOWORD(wParam), HIWORD(wParam));
break;
case AfxSig_iWww: // really AfxSig_iWiw
lResult = (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam),
(short)LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_is:
lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
break;
case AfxSig_lwl:
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
break;
case AfxSig_lwwM:
lResult = (this->*mmf.pfn_lwwM)((UINT)LOWORD(wParam),
(UINT)HIWORD(wParam), (CMenu*)CMenu::FromHandle((HMENU)lParam));
break;
case AfxSig_vv:
(this->*mmf.pfn_vv)();
break;
case AfxSig_vw: // AfxSig_vb, AfxSig_vh
(this->*mmf.pfn_vw)(wParam);
break;
case AfxSig_vww:
(this->*mmf.pfn_vww)((UINT)wParam, (UINT)lParam);
break;
case AfxSig_vvii:
(this->*mmf.pfn_vvii)((short)LOWORD(lParam), (short)HIWORD(lParam));
break;
case AfxSig_vwww:
(this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_vwii:
(this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_vwl:
(this->*mmf.pfn_vwl)(wParam, lParam);
break;
case AfxSig_vbWW:
(this->*mmf.pfn_vbWW)(m_hWnd == (HWND)lParam,
CWnd::FromHandle((HWND)lParam),
CWnd::FromHandle((HWND)wParam));
break;
case AfxSig_vD:
(this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam));
break;
case AfxSig_vM:
(this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam));
break;
case AfxSig_vMwb:
(this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam),
LOWORD(lParam), (BOOL)HIWORD(lParam));
break;
case AfxSig_vW:
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam));
break;
case AfxSig_vW2:
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)lParam));
break;
case AfxSig_vWww:
(this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam),
HIWORD(lParam));
break;
case AfxSig_vWp:
{
CPoint point((DWORD)lParam);
(this->*mmf.pfn_vWp)(CWnd::FromHandle((HWND)wParam), point);
}
break;
case AfxSig_vWh:
(this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam),
(HANDLE)lParam);
break;
case AfxSig_vwW:
(this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)lParam));
break;
case AfxSig_vwWb:
(this->*mmf.pfn_vwWb)((UINT)(LOWORD(wParam)),
CWnd::FromHandle((HWND)lParam), (BOOL)HIWORD(wParam));
break;
case AfxSig_vwwW:
case AfxSig_vwwx:
{
// special case for WM_VSCROLL and WM_HSCROLL
ASSERT(message == WM_VSCROLL || message == WM_HSCROLL ||
message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFLECT_BASE);
int nScrollCode = (short)LOWORD(wParam);
int nPos = (short)HIWORD(wParam);
if (lpEntry->nSig == AfxSig_vwwW)
(this->*mmf.pfn_vwwW)(nScrollCode, nPos,
CWnd::FromHandle((HWND)lParam));
else
(this->*mmf.pfn_vwwx)(nScrollCode, nPos);
}
break;
case AfxSig_vs:
(this->*mmf.pfn_vs)((LPTSTR)lParam);
break;
case AfxSig_vws:
(this->*mmf.pfn_vws)((UINT) wParam, (LPCTSTR)lParam);
break;
case AfxSig_vOWNER:
(this->*mmf.pfn_vOWNER)((int)wParam, (LPTSTR)lParam);
lResult = TRUE;
break;
case AfxSig_iis:
lResult = (this->*mmf.pfn_iis)((int)wParam, (LPTSTR)lParam);
break;
case AfxSig_wp:
{
CPoint point((DWORD)lParam);
lResult = (this->*mmf.pfn_wp)(point);
}
break;
case AfxSig_wv: // AfxSig_bv, AfxSig_wv
lResult = (this->*mmf.pfn_wv)();
break;
case AfxSig_vCALC:
(this->*mmf.pfn_vCALC)((BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);
break;
case AfxSig_vPOS:
(this->*mmf.pfn_vPOS)((WINDOWPOS*)lParam);
break;
case AfxSig_vwwh:
(this->*mmf.pfn_vwwh)(LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam);
break;
case AfxSig_vwp:
{
CPoint point((DWORD)lParam);
(this->*mmf.pfn_vwp)(wParam, point);
break;
}
case AfxSig_vwSIZING:
(this->*mmf.pfn_vwl)(wParam, lParam);
lResult = TRUE;
break;
case AfxSig_bwsp:
lResult = (this->*mmf.pfn_bwsp)(LOWORD(wParam), (short) HIWORD(wParam),
CPoint(LOWORD(lParam), HIWORD(lParam)));
if (!lResult)
return FALSE;
}
goto LReturnTrue;
LDispatchRegistered: // for registered windows messages
ASSERT(message >= 0xC000);
mmf.pfn = lpEntry->pfn;
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
LReturnTrue:
if (pResult != NULL)
*pResult = lResult;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CTestCmdUI - used to test for disabled commands before dispatching
class CTestCmdUI : public CCmdUI
{
public:
CTestCmdUI();
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetRadio(BOOL bOn);
virtual void SetText(LPCTSTR);
BOOL m_bEnabled;
};
CTestCmdUI::CTestCmdUI()
{
m_bEnabled = TRUE; // assume it is enabled
}
void CTestCmdUI::Enable(BOOL bOn)
{
m_bEnabled = bOn;
m_bEnableChanged = TRUE;
}
void CTestCmdUI::SetCheck(int)
{
// do nothing -- just want to know about calls to Enable
}
void CTestCmdUI::SetRadio(BOOL)
{
// do nothing -- just want to know about calls to Enable
}
void CTestCmdUI::SetText(LPCTSTR)
{
// do nothing -- just want to know about calls to Enable
}
/////////////////////////////////////////////////////////////////////////////
// CWnd command handling
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
// return TRUE if command invocation was attempted
{
UINT nID = LOWORD(wParam);
HWND hWndCtrl = (HWND)lParam;
int nCode = HIWORD(wParam);
// default routing for command messages (through closure table)
if (hWndCtrl == NULL)
{
// zero IDs for normal commands are not allowed
if (nID == 0)
return FALSE;
// make sure command has not become disabled before routing
CTestCmdUI state;
state.m_nID = nID;
OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
if (!state.m_bEnabled)
{
TRACE1("Warning: not executing disabled command %d\n", nID);
return TRUE;
}
// menu or accelerator
nCode = CN_COMMAND;
}
else
{
// control notification
ASSERT(nID == 0 || ::IsWindow(hWndCtrl));
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE; // locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl))
return TRUE; // eaten by child
// zero IDs for normal commands are not allowed
if (nID == 0)
return FALSE;
}
#ifdef _DEBUG
if (nCode < 0 && nCode != (int)0x8000)
TRACE1("Implementation Warning: control notification = $%X.\n",
nCode);
#endif
return OnCmdMsg(nID, nCode, NULL, NULL);
}
BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
{
ASSERT(pResult != NULL);
NMHDR* pNMHDR = (NMHDR*)lParam;
HWND hWndCtrl = pNMHDR->hwndFrom;
// get the child ID from the window itself
UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
int nCode = pNMHDR->code;
ASSERT(hWndCtrl != NULL);
ASSERT(::IsWindow(hWndCtrl));
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE; // locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl, pResult))
return TRUE; // eaten by child
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
}
/////////////////////////////////////////////////////////////////////////////
// CWnd extensions
CFrameWnd* CWnd::GetParentFrame() const
{
if (GetSafeHwnd() == NULL) // no Window attached
return NULL;
ASSERT_VALID(this);
CWnd* pParentWnd = GetParent(); // start with one parent up
while (pParentWnd != NULL)
{
if (pParentWnd->IsFrameWnd())
return (CFrameWnd*)pParentWnd;
pParentWnd = pParentWnd->GetParent();
}
return NULL;
}
HWND AFXAPI AfxGetParentOwner(HWND hWnd)
{
// check for permanent-owned window first
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
return pWnd->GetOwner()->GetSafeHwnd();
// otherwise, return parent in the Windows sense
return (::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) ?
::GetParent(hWnd) : ::GetWindow(hWnd, GW_OWNER);
}
CWnd* CWnd::GetTopLevelParent() const
{
if (GetSafeHwnd() == NULL) // no Window attached
return NULL;
ASSERT_VALID(this);
HWND hWndParent = m_hWnd;
HWND hWndT;
while ((hWndT = AfxGetParentOwner(hWndParent)) != NULL)
hWndParent = hWndT;
return CWnd::FromHandle(hWndParent);
}
CWnd* CWnd::GetTopLevelOwner() const
{
if (GetSafeHwnd() == NULL) // no Window attached
return NULL;
ASSERT_VALID(this);
HWND hWndOwner = m_hWnd;
HWND hWndT;
while ((hWndT = ::GetWindow(hWndOwner, GW_OWNER)) != NULL)
hWndOwner = hWndT;
return CWnd::FromHandle(hWndOwner);
}
CWnd* CWnd::GetParentOwner() const
{
if (GetSafeHwnd() == NULL) // no Window attached
return NULL;
ASSERT_VALID(this);
HWND hWndParent = m_hWnd;
HWND hWndT;
while ((::GetWindowLong(hWndParent, GWL_STYLE) & WS_CHILD) &&
(hWndT = ::GetParent(hWndParent)) != NULL)
{
hWndParent = hWndT;
}
return CWnd::FromHandle(hWndParent);
}
BOOL CWnd::IsTopParentActive() const
{
ASSERT(m_hWnd != NULL);
ASSERT_VALID(this);
return CWnd::GetForegroundWindow() ==
GetTopLevelParent()->GetLastActivePopup();
}
void CWnd::ActivateTopParent()
{
// special activate logic for floating toolbars and palettes
CWnd* pTopLevel = GetTopLevelParent();
CWnd* pActiveWnd = GetForegroundWindow();
if (pActiveWnd == NULL ||
!(pActiveWnd->m_hWnd == m_hWnd || ::IsChild(pActiveWnd->m_hWnd, m_hWnd)))
{
// clicking on floating frame when it does not have
// focus itself -- activate the toplevel frame instead.
pTopLevel->SetForegroundWindow();
}
}
CFrameWnd* CWnd::GetTopLevelFrame() const
{
if (GetSafeHwnd() == NULL) // no Window attached
return NULL;
ASSERT_VALID(this);
CFrameWnd* pFrameWnd = (CFrameWnd*)this;
if (!IsFrameWnd())
pFrameWnd = GetParentFrame();
if (pFrameWnd != NULL)
{
CFrameWnd* pTemp;
while ((pTemp = pFrameWnd->GetParentFrame()) != NULL)
pFrameWnd = pTemp;
}
return pFrameWnd;
}
CWnd* PASCAL CWnd::GetSafeOwner(CWnd* pParent, HWND* pWndTop)
{
HWND hWnd = GetSafeOwner_(pParent->GetSafeHwnd(), pWndTop);
return CWnd::FromHandle(hWnd);
}
int CWnd::MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption, UINT nType)
{
if (lpszCaption == NULL)
lpszCaption = AfxGetAppName();
int nResult = ::MessageBox(GetSafeHwnd(), lpszText, lpszCaption, nType);
return nResult;
}
CWnd* PASCAL CWnd::GetDescendantWindow(HWND hWnd, int nID, BOOL bOnlyPerm)
{
// GetDlgItem recursive (return first found)
// breadth-first for 1 level, then depth-first for next level
// use GetDlgItem since it is a fast USER function
HWND hWndChild;
CWnd* pWndChild;
if ((hWndChild = ::GetDlgItem(hWnd, nID)) != NULL)
{
if (::GetTopWindow(hWndChild) != NULL)
{
// children with the same ID as their parent have priority
pWndChild = GetDescendantWindow(hWndChild, nID, bOnlyPerm);
if (pWndChild != NULL)
return pWndChild;
}
// return temporary handle if allowed
if (!bOnlyPerm)
return CWnd::FromHandle(hWndChild);
// return only permanent handle
pWndChild = CWnd::FromHandlePermanent(hWndChild);
if (pWndChild != NULL)
return pWndChild;
}
// walk each child
for (hWndChild = ::GetTopWindow(hWnd); hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
pWndChild = GetDescendantWindow(hWndChild, nID, bOnlyPerm);
if (pWndChild != NULL)
return pWndChild;
}
return NULL; // not found
}
void PASCAL CWnd::SendMessageToDescendants(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam, BOOL bDeep, BOOL bOnlyPerm)
{
// walk through HWNDs to avoid creating temporary CWnd objects
// unless we need to call this function recursively
for (HWND hWndChild = ::GetTopWindow(hWnd); hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
// if bOnlyPerm is TRUE, don't send to non-permanent windows
if (bOnlyPerm)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
if (pWnd != NULL)
{
// call window proc directly since it is a C++ window
AfxCallWndProc(pWnd, pWnd->m_hWnd, message, wParam, lParam);
}
}
else
{
// send message with Windows SendMessage API
::SendMessage(hWndChild, message, wParam, lParam);
}
if (bDeep && ::GetTopWindow(hWndChild) != NULL)
{
// send to child windows after parent
SendMessageToDescendants(hWndChild, message, wParam, lParam,
bDeep, bOnlyPerm);
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Scroll bar helpers
// hook for CWnd functions
// only works for derived class (eg: CView) that override 'GetScrollBarCtrl'
// if the window doesn't have a _visible_ windows scrollbar - then
// look for a sibling with the appropriate ID
CScrollBar* CWnd::GetScrollBarCtrl(int) const
{
return NULL; // no special scrollers supported
}
int CWnd::SetScrollPos(int nBar, int nPos, BOOL bRedraw)
{
CScrollBar* pScrollBar;
if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
return pScrollBar->SetScrollPos(nPos, bRedraw);
else
return ::SetScrollPos(m_hWnd, nBar, nPos, bRedraw);
}
int CWnd::GetScrollPos(int nBar) const
{
CScrollBar* pScrollBar;
if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
return pScrollBar->GetScrollPos();
else
return ::GetScrollPos(m_hWnd, nBar);
}
void CWnd::SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw)
{
CScrollBar* pScrollBar;
if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
pScrollBar->SetScrollRange(nMinPos, nMaxPos, bRedraw);
else
::SetScrollRange(m_hWnd, nBar, nMinPos, nMaxPos, bRedraw);
}
void CWnd::GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const
{
CScrollBar* pScrollBar;
if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
pScrollBar->GetScrollRange(lpMinPos, lpMaxPos);
else
::GetScrollRange(m_hWnd, nBar, lpMinPos, lpMaxPos);
}
// Turn on/off non-control scrollbars
// for WS_?SCROLL scrollbars - show/hide them
// for control scrollbar - enable/disable them
void CWnd::EnableScrollBarCtrl(int nBar, BOOL bEnable)
{
CScrollBar* pScrollBar;
if (nBar == SB_BOTH)
{
EnableScrollBarCtrl(SB_HORZ, bEnable);
EnableScrollBarCtrl(SB_VERT, bEnable);
}
else if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
{
// control scrollbar - enable or disable
pScrollBar->EnableWindow(bEnable);
}
else
{
// WS_?SCROLL scrollbar - show or hide
ShowScrollBar(nBar, bEnable);
}
}
BOOL CWnd::SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw)
{
ASSERT(lpScrollInfo != NULL);
if (afxData.nWinVer < 0x333)
return FALSE;
HWND hWnd = m_hWnd;
CScrollBar* pScrollBar;
if (nBar != SB_CTL && (pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
{
hWnd = pScrollBar->m_hWnd;
nBar = SB_CTL;
}
lpScrollInfo->cbSize = sizeof(*lpScrollInfo);
::SetScrollInfo(hWnd, nBar, lpScrollInfo, bRedraw);
return TRUE;
}
BOOL CWnd::GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, UINT nMask)
{
ASSERT(lpScrollInfo != NULL);
if (afxData.nWinVer < 0x333)
return FALSE;
HWND hWnd = m_hWnd;
CScrollBar* pScrollBar;
if (nBar != SB_CTL && (pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
{
hWnd = pScrollBar->m_hWnd;
nBar = SB_CTL;
}
lpScrollInfo->cbSize = sizeof(*lpScrollInfo);
lpScrollInfo->fMask = nMask;
return ::GetScrollInfo(hWnd, nBar, lpScrollInfo);
}
int CWnd::GetScrollLimit(int nBar)
{
int nMin, nMax;
GetScrollRange(nBar, &nMin, &nMax);
SCROLLINFO info;
if (GetScrollInfo(nBar, &info, SIF_PAGE))
{
nMax -= __max(info.nPage-1,0);
}
return nMax;
}
void CWnd::ScrollWindow(int xAmount, int yAmount,
LPCRECT lpRect, LPCRECT lpClipRect)
{
ASSERT(::IsWindow(m_hWnd));
if (IsWindowVisible() || lpRect != NULL || lpClipRect != NULL)
{
// When visible, let Windows do the scrolling
::ScrollWindow(m_hWnd, xAmount, yAmount, lpRect, lpClipRect);
}
else
{
// Windows does not perform any scrolling if the window is
// not visible. This leaves child windows unscrolled.
// To account for this oversight, the child windows are moved
// directly instead.
HWND hWndChild = ::GetWindow(m_hWnd, GW_CHILD);
if (hWndChild != NULL)
{
for (; hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
CRect rect;
::GetWindowRect(hWndChild, &rect);
ScreenToClient(&rect);
::SetWindowPos(hWndChild, NULL,
rect.left+xAmount, rect.top+yAmount, 0, 0,
SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
}
}
}
#ifndef _AFX_NO_OCC_SUPPORT
if ((m_pCtrlCont == NULL) || (lpRect != NULL))
return;
// the following code is for OLE control containers only
m_pCtrlCont->ScrollChildren(xAmount, yAmount);
#endif // !_AFX_NO_OCC_SUPPORT
}
/////////////////////////////////////////////////////////////////////////////
// minimal layout support
void CWnd::RepositionBars(UINT nIDFirst, UINT nIDLast, UINT nIDLeftOver,
UINT nFlags, LPRECT lpRectParam, LPCRECT lpRectClient, BOOL bStretch)
{
ASSERT(nFlags == 0 || nFlags == reposQuery || nFlags == reposExtra);
// walk kids in order, control bars get the resize notification
// which allow them to shrink the client area
// remaining size goes to the 'nIDLeftOver' pane
// NOTE: nIDFirst->nIDLast are usually 0->0xffff
AFX_SIZEPARENTPARAMS layout;
HWND hWndLeftOver = NULL;
layout.bStretch = bStretch;
layout.sizeTotal.cx = layout.sizeTotal.cy = 0;
if (lpRectClient != NULL)
layout.rect = *lpRectClient; // starting rect comes from parameter
else
GetClientRect(&layout.rect); // starting rect comes from client rect
if (nFlags != reposQuery)
layout.hDWP = ::BeginDeferWindowPos(8); // reasonable guess
else
layout.hDWP = NULL; // not actually doing layout
for (HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
UINT nIDC = _AfxGetDlgCtrlID(hWndChild);
CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
if (nIDC == nIDLeftOver)
hWndLeftOver = hWndChild;
else if (nIDC >= nIDFirst && nIDC <= nIDLast && pWnd != NULL)
::SendMessage(hWndChild, WM_SIZEPARENT, 0, (LPARAM)&layout);
}
// if just getting the available rectangle, return it now...
if (nFlags == reposQuery)
{
ASSERT(lpRectParam != NULL);
if (bStretch)
::CopyRect(lpRectParam, &layout.rect);
else
{
lpRectParam->left = lpRectParam->top = 0;
lpRectParam->right = layout.sizeTotal.cx;
lpRectParam->bottom = layout.sizeTotal.cy;
}
return;
}
// the rest is the client size of the left-over pane
if (nIDLeftOver != 0 && hWndLeftOver != NULL)
{
CWnd* pLeftOver = CWnd::FromHandle(hWndLeftOver);
// allow extra space as specified by lpRectBorder
if (nFlags == reposExtra)
{
ASSERT(lpRectParam != NULL);
layout.rect.left += lpRectParam->left;
layout.rect.top += lpRectParam->top;
layout.rect.right -= lpRectParam->right;
layout.rect.bottom -= lpRectParam->bottom;
}
// reposition the window
pLeftOver->CalcWindowRect(&layout.rect);
AfxRepositionWindow(&layout, hWndLeftOver, &layout.rect);
}
// move and resize all the windows at once!
if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
TRACE0("Warning: DeferWindowPos failed - low system resources.\n");
}
void AFXAPI AfxRepositionWindow(AFX_SIZEPARENTPARAMS* lpLayout,
HWND hWnd, LPCRECT lpRect)
{
ASSERT(hWnd != NULL);
ASSERT(lpRect != NULL);
HWND hWndParent = ::GetParent(hWnd);
ASSERT(hWndParent != NULL);
if (lpLayout != NULL && lpLayout->hDWP == NULL)
return;
// first check if the new rectangle is the same as the current
CRect rectOld;
::GetWindowRect(hWnd, rectOld);
::ScreenToClient(hWndParent, &rectOld.TopLeft());
::ScreenToClient(hWndParent, &rectOld.BottomRight());
if (::EqualRect(rectOld, lpRect))
return; // nothing to do
// try to use DeferWindowPos for speed, otherwise use SetWindowPos
if (lpLayout != NULL)
{
lpLayout->hDWP = ::DeferWindowPos(lpLayout->hDWP, hWnd, NULL,
lpRect->left, lpRect->top, lpRect->right - lpRect->left,
lpRect->bottom - lpRect->top, SWP_NOACTIVATE|SWP_NOZORDER);
}
else
{
::SetWindowPos(hWnd, NULL, lpRect->left, lpRect->top,
lpRect->right - lpRect->left, lpRect->bottom - lpRect->top,
SWP_NOACTIVATE|SWP_NOZORDER);
}
}
void CWnd::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
DWORD dwExStyle = GetExStyle();
if (nAdjustType == 0)
dwExStyle &= ~WS_EX_CLIENTEDGE;
::AdjustWindowRectEx(lpClientRect, GetStyle(), FALSE, dwExStyle);
}
/////////////////////////////////////////////////////////////////////////////
// Special keyboard/system command processing
BOOL CWnd::HandleFloatingSysCommand(UINT nID, LPARAM lParam)
{
CWnd* pParent = GetTopLevelParent();
switch (nID & 0xfff0)
{
case SC_PREVWINDOW:
case SC_NEXTWINDOW:
if (LOWORD(lParam) == VK_F6 && pParent != NULL)
{
pParent->SetFocus();
return TRUE;
}
break;
case SC_CLOSE:
case SC_KEYMENU:
// Check lParam. If it is 0L, then the user may have done
// an Alt+Tab, so just ignore it. This breaks the ability to
// just press the Alt-key and have the first menu selected,
// but this is minor compared to what happens in the Alt+Tab
// case.
if ((nID & 0xfff0) == SC_CLOSE || lParam != 0L)
{
if (pParent != NULL)
{
// Sending the above WM_SYSCOMMAND may destroy the app,
// so we have to be careful about restoring activation
// and focus after sending it.
HWND hWndSave = m_hWnd;
HWND hWndFocus = ::GetFocus();
pParent->SetActiveWindow();
pParent->SendMessage(WM_SYSCOMMAND, nID, lParam);
// be very careful here...
if (::IsWindow(hWndSave))
::SetActiveWindow(hWndSave);
if (::IsWindow(hWndFocus))
::SetFocus(hWndFocus);
}
}
return TRUE;
}
return FALSE;
}
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
ASSERT(pMsg != NULL);
// walk from the target window up to the hWndStop window checking
// if any window wants to translate this message
for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
{
// target window is a C++ window
if (pWnd->PreTranslateMessage(pMsg))
return TRUE; // trapped by target window (eg: accelerators)
}
// got to hWndStop window without interest
if (hWnd == hWndStop)
break;
}
return FALSE; // no special processing
}
BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
return OnChildNotify(pThreadState->m_lastSentMsg.message,
pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);
}
BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
{
// get the map, and if no map, then this message does not need reflection
CHandleMap* pMap = afxMapHWND();
if (pMap == NULL)
return FALSE;
// check if in permanent map, if it is reflect it (could be OLE control)
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWndChild);
if (pWnd == NULL)
{
#ifndef _AFX_NO_OCC_SUPPORT
// check if the window is an OLE control
CWnd* pWndParent = (CWnd*)pMap->LookupPermanent(::GetParent(hWndChild));
if (pWndParent != NULL && pWndParent->m_pCtrlCont != NULL)
{
// If a matching control site exists, it's an OLE control
COleControlSite* pSite = (COleControlSite*)pWndParent->
m_pCtrlCont->m_siteMap.GetValueAt(hWndChild);
if (pSite != NULL)
{
CWnd wndTemp(hWndChild);
wndTemp.m_pCtrlSite = pSite;
LRESULT lResult = wndTemp.SendChildNotifyLastMsg(pResult);
wndTemp.m_hWnd = NULL;
return lResult;
}
}
#endif //!_AFX_NO_OCC_SUPPORT
return FALSE;
}
// only OLE controls and permanent windows will get reflected msgs
ASSERT(pWnd != NULL);
return pWnd->SendChildNotifyLastMsg(pResult);
}
BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
#ifndef _AFX_NO_OCC_SUPPORT
if (m_pCtrlSite != NULL)
{
// first forward raw OCM_ messages to OLE control sources
LRESULT lResult = SendMessage(OCM__BASE+uMsg, wParam, lParam);
if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC &&
(HBRUSH)lResult == NULL)
{
// for WM_CTLCOLOR msgs, returning NULL implies continue routing
return FALSE;
}
if (pResult != NULL)
*pResult = lResult;
return TRUE;
}
#endif
return ReflectChildNotify(uMsg, wParam, lParam, pResult);
}
BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// Note: reflected messages are send directly to CWnd::OnWndMsg
// and CWnd::OnCmdMsg for speed and because these messages are not
// routed by normal OnCmdMsg routing (they are only dispatched)
switch (uMsg)
{
// normal messages (just wParam, lParam through OnWndMsg)
case WM_HSCROLL:
case WM_VSCROLL:
case WM_PARENTNOTIFY:
case WM_DRAWITEM:
case WM_MEASUREITEM:
case WM_DELETEITEM:
case WM_VKEYTOITEM:
case WM_CHARTOITEM:
case WM_COMPAREITEM:
// reflect the message through the message map as WM_REFLECT_BASE+uMsg
return CWnd::OnWndMsg(WM_REFLECT_BASE+uMsg, wParam, lParam, pResult);
// special case for WM_COMMAND
case WM_COMMAND:
{
// reflect the message through the message map as OCM_COMMAND
int nCode = HIWORD(wParam);
if (CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_COMMAND), NULL, NULL))
{
if (pResult != NULL)
*pResult = 1;
return TRUE;
}
}
break;
// special case for WM_NOTIFY
case WM_NOTIFY:
{
// reflect the message through the message map as OCM_NOTIFY
NMHDR* pNMHDR = (NMHDR*)lParam;
int nCode = pNMHDR->code;
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL);
}
// other special cases (WM_CTLCOLOR family)
default:
if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC)
{
// fill in special struct for compatiblity with 16-bit WM_CTLCOLOR
AFX_CTLCOLOR ctl;
ctl.hDC = (HDC)wParam;
ctl.nCtlType = uMsg - WM_CTLCOLORMSGBOX;
ASSERT(ctl.nCtlType >= CTLCOLOR_MSGBOX);
ASSERT(ctl.nCtlType <= CTLCOLOR_STATIC);
// reflect the message through the message map as OCM_CTLCOLOR
BOOL bResult = CWnd::OnWndMsg(WM_REFLECT_BASE+WM_CTLCOLOR, 0, (LPARAM)&ctl, pResult);
if ((HBRUSH)*pResult == NULL)
bResult = FALSE;
return bResult;
}
break;
}
return FALSE; // let the parent handle it
}
void CWnd::OnParentNotify(UINT message, LPARAM lParam)
{
if ((LOWORD(message) == WM_CREATE || LOWORD(message) == WM_DESTROY))
{
if (ReflectLastMsg((HWND)lParam))
return; // eat it
}
// not handled - do default
Default();
}
LRESULT CWnd::OnActivateTopLevel(WPARAM wParam, LPARAM)
{
if (LOWORD(wParam) == WA_INACTIVE)
{
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
if (!(pThreadState->m_lastInfo.uFlags & TTF_ALWAYSTIP))
CancelToolTips(TRUE);
}
return 0;
}
void CWnd::OnSysColorChange()
{
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
// recolor global brushes used by control bars
afxData.UpdateSysColors();
}
#ifndef _AFX_NO_CTL3D_SUPPORT
if (!afxContextIsDLL)
{
if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this)
{
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
// allow CTL3D32.DLL to be notified of color change
if (pCtl3dState->m_pfnColorChange != NULL)
(*pCtl3dState->m_pfnColorChange)();
}
}
#endif
// forward this message to all other child windows
if (!(GetStyle() & WS_CHILD))
SendMessageToDescendants(WM_SYSCOLORCHANGE, 0, 0L, TRUE, TRUE);
Default();
}
BOOL _afxGotScrollLines;
void CWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
UNUSED_ALWAYS(uFlags);
UNUSED_ALWAYS(lpszSection);
#ifndef _AFX_NO_CTL3D_SUPPORT
if (!afxContextIsDLL)
{
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
// allow CTL3D32.DLL to update from WIN.INI settings
if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this &&
pCtl3dState->m_pfnWinIniChange != NULL)
{
(*pCtl3dState->m_pfnWinIniChange)();
}
}
#endif
// force refresh of settings that we cache
_afxGotScrollLines = FALSE;
CWnd::OnDisplayChange(0, 0); // to update system metrics, etc.
}
void CWnd::OnWinIniChange(LPCTSTR lpszSection)
{
UNUSED_ALWAYS(lpszSection);
// this function is provided for backward compatibility only
// it is called only in Windows NT 3.51; in Windows 95 and
// Windows NT, OnSettingChange is called
#ifndef _AFX_NO_CTL3D_SUPPORT
if (!afxContextIsDLL)
{
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
// allow CTL3D32.DLL to update from WIN.INI settings
if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this &&
pCtl3dState->m_pfnWinIniChange != NULL)
{
(*pCtl3dState->m_pfnWinIniChange)();
}
}
#endif
CWnd::OnDisplayChange(0, 0); // to update system metrics, etc.
}
void CWnd::OnDevModeChange(LPTSTR lpDeviceName)
{
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
pApp->DevModeChange(lpDeviceName);
// forward this message to all other child windows
if (!(GetStyle() & WS_CHILD))
{
const MSG* pMsg = GetCurrentMessage();
SendMessageToDescendants(pMsg->message, pMsg->wParam, pMsg->lParam,
TRUE, TRUE);
}
}
BOOL CWnd::OnHelpInfo(HELPINFO* /*pHelpInfo*/)
{
if (!(GetStyle() & WS_CHILD))
{
CWnd* pMainWnd = AfxGetMainWnd();
if (pMainWnd != NULL &&
GetKeyState(VK_SHIFT) >= 0 &&
GetKeyState(VK_CONTROL) >= 0 &&
GetKeyState(VK_MENU) >= 0)
{
pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
return TRUE;
}
}
return Default();
}
LRESULT CWnd::OnDisplayChange(WPARAM, LPARAM)
{
// update metrics if this window is the main window
if (AfxGetMainWnd() == this)
{
// update any system metrics cache
afxData.UpdateSysMetrics();
}
// forward this message to all other child windows
if (!(GetStyle() & WS_CHILD))
{
const MSG* pMsg = GetCurrentMessage();
SendMessageToDescendants(pMsg->message, pMsg->wParam, pMsg->lParam,
TRUE, TRUE);
}
return Default();
}
LRESULT CWnd::OnDragList(WPARAM, LPARAM lParam)
{
LPDRAGLISTINFO lpInfo = (LPDRAGLISTINFO)lParam;
ASSERT(lpInfo != NULL);
LRESULT lResult;
if (ReflectLastMsg(lpInfo->hWnd, &lResult))
return (int)lResult; // eat it
// not handled - do default
return (int)Default();
}
void CWnd::OnHScroll(UINT, UINT, CScrollBar* pScrollBar)
{
if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
return; // eat it
Default();
}
void CWnd::OnVScroll(UINT, UINT, CScrollBar* pScrollBar)
{
if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
return; // eat it
Default();
}
void CWnd::OnEnterIdle(UINT /*nWhy*/, CWnd* /*pWho*/)
{
// WINBUG: In some OLE inplace active scenarios, OLE will post a
// message instead of sending it. This causes so many WM_ENTERIDLE
// messages to be sent that tasks running in the background stop
// running. By dispatching the pending WM_ENTERIDLE messages
// when the first one is received, we trick Windows into thinking
// that only one was really sent and dispatched.
{
MSG msg;
while (PeekMessage(&msg, NULL, WM_ENTERIDLE, WM_ENTERIDLE, PM_REMOVE))
DispatchMessage(&msg);
}
Default();
}
HBRUSH CWnd::OnCtlColor(CDC*, CWnd* pWnd, UINT)
{
ASSERT(pWnd != NULL && pWnd->m_hWnd != NULL);
LRESULT lResult;
if (pWnd->SendChildNotifyLastMsg(&lResult))
return (HBRUSH)lResult; // eat it
return (HBRUSH)Default();
}
#ifndef _AFX_NO_GRAYDLG_SUPPORT
// special helper for Gray OnCtlColor routines
HBRUSH CWnd::OnGrayCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
LRESULT lResult;
if (pWnd->SendChildNotifyLastMsg(&lResult))
return (HBRUSH)lResult; // eat it
_AFX_WIN_STATE* pWinState = _afxWinState;
if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
pWinState->m_hDlgBkBrush, pWinState->m_crDlgTextClr))
return (HBRUSH)Default();
return pWinState->m_hDlgBkBrush;
}
#endif //!_AFX_NO_GRAYDLG_SUPPORT
// implementation of OnCtlColor for default gray backgrounds
// (works for any window containing controls)
// return value of FALSE means caller must call DefWindowProc's default
// TRUE means that 'hbrGray' will be used and the appropriate text
// ('clrText') and background colors are set.
BOOL PASCAL CWnd::GrayCtlColor(HDC hDC, HWND hWnd, UINT nCtlColor,
HBRUSH hbrGray, COLORREF clrText)
{
if (hDC == NULL)
{
// sometimes Win32 passes a NULL hDC in the WM_CTLCOLOR message.
TRACE0("Warning: hDC is NULL in CWnd::GrayCtlColor; WM_CTLCOLOR not processed.\n");
return FALSE;
}
if (hbrGray == NULL ||
nCtlColor == CTLCOLOR_EDIT || nCtlColor == CTLCOLOR_MSGBOX ||
nCtlColor == CTLCOLOR_SCROLLBAR)
{
return FALSE;
}
if (nCtlColor == CTLCOLOR_LISTBOX)
{
// only handle requests to draw the space between edit and drop button
// in a drop-down combo (not a drop-down list)
if (!_AfxIsComboBoxControl(hWnd, (UINT)CBS_DROPDOWN))
return FALSE;
}
// set background color and return handle to brush
LOGBRUSH logbrush;
VERIFY(::GetObject(hbrGray, sizeof(LOGBRUSH), (LPVOID)&logbrush));
::SetBkColor(hDC, logbrush.lbColor);
if (clrText == (COLORREF)-1)
clrText = ::GetSysColor(COLOR_WINDOWTEXT); // normal text
::SetTextColor(hDC, clrText);
return TRUE;
}
#ifndef _AFX_NO_CTL3D_SUPPORT
LRESULT CWnd::OnQuery3dControls(WPARAM, LPARAM)
{
// This is message handler is not in CWnd's message map.
// It is placed in various derived classes' message maps to enable
// 3D controls for specific window types only.
return 0xFFFF; // CTL3D_ALL
}
#endif
/////////////////////////////////////////////////////////////////////////////
// 'dialog data' support
BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
{
ASSERT(::IsWindow(m_hWnd)); // calling UpdateData before DoModal?
CDataExchange dx(this, bSaveAndValidate);
// prevent control notifications from being dispatched during UpdateData
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow;
ASSERT(hWndOldLockout != m_hWnd); // must not recurse
pThreadState->m_hLockoutNotifyWindow = m_hWnd;
BOOL bOK = FALSE; // assume failure
TRY
{
DoDataExchange(&dx);
bOK = TRUE; // it worked
}
CATCH(CUserException, e)
{
// validation failed - user already alerted, fall through
ASSERT(!bOK);
// Note: DELETE_EXCEPTION_(e) not required
}
AND_CATCH_ALL(e)
{
// validation failed due to OOM or other resource failure
e->ReportError(MB_ICONEXCLAMATION, AFX_IDP_INTERNAL_FAILURE);
ASSERT(!bOK);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThreadState->m_hLockoutNotifyWindow = hWndOldLockout;
return bOK;
}
CDataExchange::CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate)
{
ASSERT_VALID(pDlgWnd);
m_bSaveAndValidate = bSaveAndValidate;
m_pDlgWnd = pDlgWnd;
m_hWndLastControl = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// Centering dialog support (works for any non-child window)
void CWnd::CenterWindow(CWnd* pAlternateOwner)
{
ASSERT(::IsWindow(m_hWnd));
// determine owner window to center against
DWORD dwStyle = GetStyle();
HWND hWndCenter = pAlternateOwner->GetSafeHwnd();
if (pAlternateOwner == NULL)
{
if (dwStyle & WS_CHILD)
hWndCenter = ::GetParent(m_hWnd);
else
hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
if (hWndCenter != NULL)
{
// let parent determine alternate center window
HWND hWndTemp =
(HWND)::SendMessage(hWndCenter, WM_QUERYCENTERWND, 0, 0);
if (hWndTemp != NULL)
hWndCenter = hWndTemp;
}
}
// get coordinates of the window relative to its parent
CRect rcDlg;
GetWindowRect(&rcDlg);
CRect rcArea;
CRect rcCenter;
HWND hWndParent;
if (!(dwStyle & WS_CHILD))
{
// don't center against invisible or minimized windows
if (hWndCenter != NULL)
{
DWORD dwStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_MINIMIZE))
hWndCenter = NULL;
}
MONITORINFO mi;
mi.cbSize = sizeof(mi);
// center within appropriate monitor coordinates
if (hWndCenter == NULL)
{
HWND hwDefault = AfxGetMainWnd()->GetSafeHwnd();
GetMonitorInfo(
MonitorFromWindow(hwDefault, MONITOR_DEFAULTTOPRIMARY), &mi);
rcCenter = mi.rcWork;
rcArea = mi.rcWork;
}
else
{
::GetWindowRect(hWndCenter, &rcCenter);
GetMonitorInfo(
MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST), &mi);
rcArea = mi.rcWork;
}
}
else
{
// center within parent client coordinates
hWndParent = ::GetParent(m_hWnd);
ASSERT(::IsWindow(hWndParent));
::GetClientRect(hWndParent, &rcArea);
ASSERT(::IsWindow(hWndCenter));
::GetClientRect(hWndCenter, &rcCenter);
::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
}
// find dialog's upper left based on rcCenter
int xLeft = (rcCenter.left + rcCenter.right) / 2 - rcDlg.Width() / 2;
int yTop = (rcCenter.top + rcCenter.bottom) / 2 - rcDlg.Height() / 2;
// if the dialog is outside the screen, move it inside
if (xLeft < rcArea.left)
xLeft = rcArea.left;
else if (xLeft + rcDlg.Width() > rcArea.right)
xLeft = rcArea.right - rcDlg.Width();
if (yTop < rcArea.top)
yTop = rcArea.top;
else if (yTop + rcDlg.Height() > rcArea.bottom)
yTop = rcArea.bottom - rcDlg.Height();
// map screen coordinates to child coordinates
SetWindowPos(NULL, xLeft, yTop, -1, -1,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
BOOL CWnd::CheckAutoCenter()
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Dialog initialization support
BOOL CWnd::ExecuteDlgInit(LPCTSTR lpszResourceName)
{
// find resource handle
LPVOID lpResource = NULL;
HGLOBAL hResource = NULL;
if (lpszResourceName != NULL)
{
HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_DLGINIT);
HRSRC hDlgInit = ::FindResource(hInst, lpszResourceName, RT_DLGINIT);
if (hDlgInit != NULL)
{
// load it
hResource = LoadResource(hInst, hDlgInit);
if (hResource == NULL)
return FALSE;
// lock it
lpResource = LockResource(hResource);
ASSERT(lpResource != NULL);
}
}
// execute it
BOOL bResult = ExecuteDlgInit(lpResource);
// cleanup
if (lpResource != NULL && hResource != NULL)
{
UnlockResource(hResource);
FreeResource(hResource);
}
return bResult;
}
BOOL CWnd::ExecuteDlgInit(LPVOID lpResource)
{
BOOL bSuccess = TRUE;
if (lpResource != NULL)
{
UNALIGNED WORD* lpnRes = (WORD*)lpResource;
while (bSuccess && *lpnRes != 0)
{
WORD nIDC = *lpnRes++;
WORD nMsg = *lpnRes++;
DWORD dwLen = *((UNALIGNED DWORD*&)lpnRes)++;
// In Win32 the WM_ messages have changed. They have
// to be translated from the 32-bit values to 16-bit
// values here.
#define WIN16_LB_ADDSTRING 0x0401
#define WIN16_CB_ADDSTRING 0x0403
#define AFX_CB_ADDSTRING 0x1234
// unfortunately, WIN16_CB_ADDSTRING == CBEM_INSERTITEM
if (nMsg == AFX_CB_ADDSTRING)
nMsg = CBEM_INSERTITEM;
else if (nMsg == WIN16_LB_ADDSTRING)
nMsg = LB_ADDSTRING;
else if (nMsg == WIN16_CB_ADDSTRING)
nMsg = CB_ADDSTRING;
// check for invalid/unknown message types
#ifdef _AFX_NO_OCC_SUPPORT
ASSERT(nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING ||
nMsg == CBEM_INSERTITEM);
#else
ASSERT(nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING ||
nMsg == CBEM_INSERTITEM ||
nMsg == WM_OCC_LOADFROMSTREAM ||
nMsg == WM_OCC_LOADFROMSTREAM_EX ||
nMsg == WM_OCC_LOADFROMSTORAGE ||
nMsg == WM_OCC_LOADFROMSTORAGE_EX ||
nMsg == WM_OCC_INITNEW);
#endif
#ifdef _DEBUG
// For AddStrings, the count must exactly delimit the
// string, including the NULL termination. This check
// will not catch all mal-formed ADDSTRINGs, but will
// catch some.
if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING || nMsg == CBEM_INSERTITEM)
ASSERT(*((LPBYTE)lpnRes + (UINT)dwLen - 1) == 0);
#endif
if (nMsg == CBEM_INSERTITEM)
{
USES_CONVERSION;
COMBOBOXEXITEM item;
item.mask = CBEIF_TEXT;
item.iItem = -1;
item.pszText = A2T(LPSTR(lpnRes));
if (::SendDlgItemMessage(m_hWnd, nIDC, nMsg, 0, (LPARAM) &item) == -1)
bSuccess = FALSE;
}
#ifndef _AFX_NO_OCC_SUPPORT
else if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING)
#endif // !_AFX_NO_OCC_SUPPORT
{
// List/Combobox returns -1 for error
if (::SendDlgItemMessageA(m_hWnd, nIDC, nMsg, 0, (LPARAM) lpnRes) == -1)
bSuccess = FALSE;
}
// skip past data
lpnRes = (WORD*)((LPBYTE)lpnRes + (UINT)dwLen);
}
}
// send update message to all controls after all other siblings loaded
if (bSuccess)
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, FALSE, FALSE);
return bSuccess;
}
void CWnd::UpdateDialogControls(CCmdTarget* pTarget, BOOL bDisableIfNoHndler)
{
CCmdUI state;
CWnd wndTemp; // very temporary window just for CmdUI update
// walk all the kids - assume the IDs are for buttons
for (HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
// send to buttons
wndTemp.m_hWnd = hWndChild; // quick and dirty attach
state.m_nID = _AfxGetDlgCtrlID(hWndChild);
state.m_pOther = &wndTemp;
// check for reflect handlers in the child window
CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
if (pWnd != NULL)
{
// call it directly to disable any routing
if (pWnd->CWnd::OnCmdMsg(0, MAKELONG(-1,
WM_COMMAND+WM_REFLECT_BASE), &state, NULL))
continue;
}
// check for handlers in the parent window
if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
continue;
// determine whether to disable when no handler exists
BOOL bDisableTemp = bDisableIfNoHndler;
if (bDisableTemp)
{
if ((wndTemp.SendMessage(WM_GETDLGCODE) & DLGC_BUTTON) == 0)
{
// non-button controls don't get automagically disabled
bDisableTemp = FALSE;
}
else
{
// only certain button controls get automagically disabled
UINT nStyle = (UINT)(wndTemp.GetStyle() & 0x0F);
if (nStyle == (UINT)BS_AUTOCHECKBOX ||
nStyle == (UINT)BS_AUTO3STATE ||
nStyle == (UINT)BS_GROUPBOX ||
nStyle == (UINT)BS_AUTORADIOBUTTON)
{
bDisableTemp = FALSE;
}
}
}
// check for handlers in the target (owner)
state.DoUpdate(pTarget, bDisableTemp);
}
wndTemp.m_hWnd = NULL; // quick and dirty detach
}
BOOL CWnd::PreTranslateInput(LPMSG lpMsg)
{
ASSERT(::IsWindow(m_hWnd));
// don't translate non-input events
if ((lpMsg->message < WM_KEYFIRST || lpMsg->message > WM_KEYLAST) &&
(lpMsg->message < WM_MOUSEFIRST || lpMsg->message > WM_MOUSELAST))
return FALSE;
return IsDialogMessage(lpMsg);
}
int CWnd::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); // window must be created
ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG* pMsg = &AfxGetThread()->m_msgCur;
// acquire and dispatch messages until the modal state is done
for (;;)
{
ASSERT(ContinueModal());
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// call OnIdle while in bIdle state
if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
{
// send WM_ENTERIDLE to the parent
::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
{
// stop idle processing next time
bIdle = FALSE;
}
}
// phase2: pump messages while available
do
{
ASSERT(ContinueModal());
// pump message, but quit on WM_QUIT
if (!AfxGetThread()->PumpMessage())
{
AfxPostQuitMessage(0);
return -1;
}
// show the window when certain special messages rec'd
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())
goto ExitModal;
// reset "no idle" state after pumping "normal" message
if (AfxGetThread()->IsIdleMessage(pMsg))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}
BOOL CWnd::ContinueModal()
{
return m_nFlags & WF_CONTINUEMODAL;
}
void CWnd::EndModalLoop(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
// this result will be returned from CWnd::RunModalLoop
m_nModalResult = nResult;
// make sure a message goes through to exit the modal loop
if (m_nFlags & WF_CONTINUEMODAL)
{
m_nFlags &= ~WF_CONTINUEMODAL;
PostMessage(WM_NULL);
}
}
#ifndef _AFX_NO_OCC_SUPPORT
BOOL CWnd::SetOccDialogInfo(_AFX_OCC_DIALOG_INFO*)
{
ASSERT(FALSE); // this class doesn't support dialog creation
return FALSE;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Standard init called by WinMain
AFX_STATIC BOOL AFXAPI _AfxRegisterWithIcon(WNDCLASS* pWndCls,
LPCTSTR lpszClassName, UINT nIDIcon)
{
pWndCls->lpszClassName = lpszClassName;
HINSTANCE hInst = AfxFindResourceHandle(
MAKEINTRESOURCE(nIDIcon), RT_GROUP_ICON);
if ((pWndCls->hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDIcon))) == NULL)
{
// use default icon
pWndCls->hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
}
return AfxRegisterClass(pWndCls);
}
LONG AFXAPI _AfxInitCommonControls(LPINITCOMMONCONTROLSEX lpInitCtrls, LONG fToRegister)
{
ASSERT(fToRegister != 0);
#ifndef _AFXDLL
HINSTANCE hInstBefore = ::GetModuleHandleA("COMCTL32.DLL");
#endif
// load the COMCTL32.DLL library because it may not be loaded yet (delayload)
HINSTANCE hInst = ::LoadLibraryA("COMCTL32.DLL");
if (hInst == NULL)
return 0;
LONG lResult = 0;
// attempt to get/call InitCommonControlsEx
BOOL (STDAPICALLTYPE* pfnInit)(LPINITCOMMONCONTROLSEX lpInitCtrls) = NULL;
(FARPROC&)pfnInit = ::GetProcAddress(hInst, "InitCommonControlsEx");
if (pfnInit == NULL)
{
// not there, so call InitCommonControls if possible
if ((fToRegister & AFX_WIN95CTLS_MASK) == fToRegister)
{
InitCommonControls();
lResult = AFX_WIN95CTLS_MASK;
}
}
#ifdef _AFXDLL
else if (InitCommonControlsEx(lpInitCtrls))
#else
else if ((*pfnInit)(lpInitCtrls))
#endif
{
// InitCommonControlsEx was successful so return the full mask
lResult = fToRegister;
#ifndef _AFXDLL
if (hInstBefore == NULL)
{
// In the case that we are statically linked and COMCTL32.DLL
// was not loaded before we loaded it with LoadLibrary in this
// function, that indicates that the calling module is linked
// with /delayload:comctl32.dll, and in this case we have to do
// something to cause COMCTL32.DLL to stay loaded. The only thing
// we can do is to call a COMCTL32.DLL API which will cause the
// CRT's delay load helpers to get called and will cause the DLL
// to get loaded. We choose to call InitCommonControls because
// it exists in the original COMCTL32.DLL and it doesn't really
// do any harm to call it, except for the time it takes to
// register the set of original Windows 95 classes.
// If this isn't done our FreeLibrary call below will cause
// COMCTL32.DLL to go away, undoing the registration.
InitCommonControls();
lResult |= AFX_WIN95CTLS_MASK;
}
#endif
}
// free the library reference and return the result
FreeLibrary(hInst);
return lResult;
}
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{
// mask off all classes that are already registered
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
fToRegister &= ~pModuleState->m_fRegisteredClasses;
if (fToRegister == 0)
return TRUE;
LONG fRegisteredClasses = 0;
// common initialization
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults
wndcls.lpfnWndProc = DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hCursor = afxData.hcurArrow;
INITCOMMONCONTROLSEX init;
init.dwSize = sizeof(init);
// work to register classes as specified by fToRegister, populate fRegisteredClasses as we go
if (fToRegister & AFX_WND_REG)
{
// Child windows - no brush, no icon, safest default class styles
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpszClassName = _afxWnd;
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WND_REG;
}
if (fToRegister & AFX_WNDOLECONTROL_REG)
{
// OLE Control windows - use parent DC for speed
wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpszClassName = _afxWndOleControl;
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WNDOLECONTROL_REG;
}
if (fToRegister & AFX_WNDCONTROLBAR_REG)
{
// Control bar windows
wndcls.style = 0; // control bars don't handle double click
wndcls.lpszClassName = _afxWndControlBar;
wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;
}
if (fToRegister & AFX_WNDMDIFRAME_REG)
{
// MDI Frame window (also used for splitter window)
wndcls.style = CS_DBLCLKS;
wndcls.hbrBackground = NULL;
if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))
fRegisteredClasses |= AFX_WNDMDIFRAME_REG;
}
if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
{
// SDI Frame or MDI Child windows or views - normal colors
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))
fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;
}
if (fToRegister & AFX_WNDCOMMCTLS_REG)
{
// this flag is compatible with the old InitCommonControls() API
init.dwICC = ICC_WIN95_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);
fToRegister &= ~AFX_WIN95CTLS_MASK;
}
if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)
{
init.dwICC = ICC_UPDOWN_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG)
{
init.dwICC = ICC_TREEVIEW_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_TAB_REG)
{
init.dwICC = ICC_TAB_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TAB_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG)
{
init.dwICC = ICC_PROGRESS_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PROGRESS_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG)
{
init.dwICC = ICC_LISTVIEW_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG)
{
init.dwICC = ICC_HOTKEY_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_BAR_REG)
{
init.dwICC = ICC_BAR_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG)
{
init.dwICC = ICC_ANIMATE_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ANIMATE_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG)
{
init.dwICC = ICC_INTERNET_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_COOL_REG)
{
init.dwICC = ICC_COOL_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG)
{
init.dwICC = ICC_USEREX_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)
{
init.dwICC = ICC_DATE_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG);
}
// save new state of registered controls
pModuleState->m_fRegisteredClasses |= fRegisteredClasses;
// special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG
if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK)
{
pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
}
// must have registered at least as mamy classes as requested
return (fToRegister & fRegisteredClasses) == fToRegister;
}
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd (here for library granularity)
BOOL CWnd::IsFrameWnd() const
{
return FALSE;
}
BOOL CFrameWnd::IsFrameWnd() const
{
return TRUE;
}
BOOL CFrameWnd::IsTracking() const
{
return m_nIDTracking != 0 &&
m_nIDTracking != AFX_IDS_HELPMODEMESSAGE &&
m_nIDTracking != AFX_IDS_IDLEMESSAGE;
}
/////////////////////////////////////////////////////////////////////////////
// CTL3D support
#ifndef _AFX_NO_CTL3D_SUPPORT
// Use SubclassCtl3d to add CTL3D support to an already subclassed control
// Usually only necessary if the control does not have one of the standard
// Windows class names.
BOOL CWnd::SubclassCtl3d(int nControlType)
{
ASSERT(!afxContextIsDLL); // Should only be called by apps
if (afxContextIsDLL)
return FALSE;
ASSERT(m_hWnd != NULL);
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
if (nControlType == -1)
{
if (pCtl3dState->m_pfnSubclassCtl != NULL)
return (*pCtl3dState->m_pfnSubclassCtl)(m_hWnd);
}
else
{
if (pCtl3dState->m_pfnSubclassCtlEx != NULL)
return (*pCtl3dState->m_pfnSubclassCtlEx)(m_hWnd, nControlType);
}
return FALSE;
}
// Use SubclassDlg3d to add CTL3D support to an entire window.
// Any windows created on the window will be automatically subclassed.
BOOL CWnd::SubclassDlg3d(DWORD dwMask)
{
ASSERT(!afxContextIsDLL); // Should only be called by apps
if (afxContextIsDLL)
return FALSE;
ASSERT(m_hWnd != NULL);
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
if (pCtl3dState->m_pfnSubclassDlgEx != NULL)
return pCtl3dState->m_pfnSubclassDlgEx(m_hWnd, dwMask);
return FALSE;
}
#endif //!_AFX_NO_CTL3D_SUPPORT
//this function can't be inlined because of _afxShell
void CWnd::DragAcceptFiles(BOOL bAccept)
{
ASSERT(::IsWindow(m_hWnd));
::DragAcceptFiles(m_hWnd, bAccept);
}
/////////////////////////////////////////////////////////////////////////////
// Extra CWnd support for dynamic subclassing of controls
BOOL CWnd::SubclassWindow(HWND hWnd)
{
if (!Attach(hWnd))
return FALSE;
// allow any other subclassing to occur
PreSubclassWindow();
// now hook into the AFX WndProc
WNDPROC* lplpfn = GetSuperWndProcAddr();
WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)AfxGetAfxWndProc());
ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());
if (*lplpfn == NULL)
*lplpfn = oldWndProc; // the first control of that type created
#ifdef _DEBUG
else if (*lplpfn != oldWndProc)
{
TRACE0("Error: Trying to use SubclassWindow with incorrect CWnd\n");
TRACE0("\tderived class.\n");
TRACE3("\thWnd = $%04X (nIDC=$%04X) is not a %hs.\n", (UINT)hWnd,
_AfxGetDlgCtrlID(hWnd), GetRuntimeClass()->m_lpszClassName);
ASSERT(FALSE);
// undo the subclassing if continuing after assert
::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
}
#endif
return TRUE;
}
BOOL CWnd::SubclassDlgItem(UINT nID, CWnd* pParent)
{
ASSERT(pParent != NULL);
ASSERT(::IsWindow(pParent->m_hWnd));
// check for normal dialog control first
HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, nID);
if (hWndControl != NULL)
return SubclassWindow(hWndControl);
#ifndef _AFX_NO_OCC_SUPPORT
if (pParent->m_pCtrlCont != NULL)
{
// normal dialog control not found
COleControlSite* pSite = pParent->m_pCtrlCont->FindItem(nID);
if (pSite != NULL)
{
ASSERT(pSite->m_hWnd != NULL);
VERIFY(SubclassWindow(pSite->m_hWnd));
#ifndef _AFX_NO_OCC_SUPPORT
// If the control has reparented itself (e.g., invisible control),
// make sure that the CWnd gets properly wired to its control site.
if (pParent->m_hWnd != ::GetParent(pSite->m_hWnd))
AttachControlSite(pParent);
#endif //!_AFX_NO_OCC_SUPPORT
return TRUE;
}
}
#endif
return FALSE; // control not found
}
HWND CWnd::UnsubclassWindow()
{
ASSERT(::IsWindow(m_hWnd));
// set WNDPROC back to original value
WNDPROC* lplpfn = GetSuperWndProcAddr();
SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)*lplpfn);
*lplpfn = NULL;
// and Detach the HWND from the CWnd object
return Detach();
}
////////////////////////////////////////////////////////////////////////////
// out-of-line inlines for binary compatibility
#ifdef _AFXDLL
#ifndef _DEBUG
CPoint::CPoint(POINT initPt)
{ *(POINT*)this = initPt; }
#endif
#endif
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
IMPLEMENT_DYNCREATE(CTempWnd, CWnd);
#pragma warning(disable: 4074)
#pragma init_seg(compiler)
IMPLEMENT_FIXED_ALLOC(CTempWnd, 64);
/////////////////////////////////////////////////////////////////////////////