Skip to content

Instantly share code, notes, and snippets.

@thinkhy
Created January 25, 2011 10:07
Show Gist options
  • Save thinkhy/794742 to your computer and use it in GitHub Desktop.
Save thinkhy/794742 to your computer and use it in GitHub Desktop.
MFC_wincore
#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)
#include <atlacc.h> // Accessible Proxy from ATL
#include "sal.h"
// for dll builds we just delay load it
#ifndef _AFXDLL
PROCESS_LOCAL(_AFX_HTMLHELP_STATE, _afxHtmlHelpState)
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Globals
const UINT CWnd::m_nMsgDragList = ::RegisterWindowMessage(DRAGLISTMSGSTRING);
CWnd::PFNNOTIFYWINEVENT CWnd::m_pfnNotifyWinEvent = NULL;
// 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()
{
m_hWnd = NULL;
m_bEnableActiveAccessibility = false;
m_pProxy = NULL;
m_pStdObject = NULL;
m_hWndOwner = NULL;
m_nFlags = 0;
m_pfnSuper = NULL;
m_nModalResult = 0;
m_pDropTarget = NULL;
#ifndef _AFX_NO_OCC_SUPPORT
m_pCtrlCont = NULL;
m_pCtrlSite = NULL;
#endif
}
CWnd::CWnd(HWND hWnd)
{
m_hWnd = hWnd;
m_bEnableActiveAccessibility = false;
m_pProxy = NULL;
m_hWndOwner = NULL;
m_nFlags = 0;
m_pfnSuper = NULL;
m_nModalResult = 0;
m_pDropTarget = NULL;
#ifndef _AFX_NO_OCC_SUPPORT
m_pCtrlCont = NULL;
m_pCtrlSite = NULL;
#endif
}
// 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
if (!(pWnd->GetStyle() & WS_CHILD))
{
CWnd* pTopLevel= pWnd->GetTopLevelParent();
if (pTopLevel && (pWndOther == NULL || !::IsWindow(pWndOther->m_hWnd) || pTopLevel != 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
_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 = AfxProcessWndProcException(e, &pThreadState->m_lastSentMsg);
TRACE(traceAppMsg, 0, "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*
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(CWnd),
ConstructDestruct<CWnd>::Construct, ConstructDestruct<CWnd>::Destruct,
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
}
/////////////////////////////////////////////////////////////////////////////
// CMenu functions
CMenu* CWnd::GetMenu() const
{
ASSERT(::IsWindow(m_hWnd));
return CMenu::FromHandle(::GetMenu(m_hWnd));
}
BOOL CWnd::SetMenu(CMenu* pMenu)
{
ASSERT(::IsWindow(m_hWnd));
return ::SetMenu(m_hWnd, pMenu->GetSafeHmenu());
}
////////////////////////////////////////////////////////////////////////////
// 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==NULL || pWnd->m_hWnd == hWnd);
if (pWnd == NULL || pWnd->m_hWnd != hWnd)
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
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:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<INT_PTR>(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 = AfxProcessWndProcException(e, &msg);
TRACE(traceAppMsg, 0, "Warning: Uncaught exception in _AfxActivationWndProc (returning %ld).\n",
lResult);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return lResult;
}
/////////////////////////////////////////////////////////////////////////////
// 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 (DWORD_PTR(lpcs->lpszClass) > 0xffff)
{
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 (::AfxInvariantStrICmp(pszClassName, _T("ime")) == 0)
goto lCallNextHook;
}
ASSERT(wParam != NULL); // should be non-NULL HWND
HWND hWnd = (HWND)wParam;
WNDPROC oldWndProc;
if (pWndInit != NULL)
{
AFX_MANAGE_STATE(pWndInit->m_pModuleState);
// 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);
// subclass the window with standard AfxWndProc
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,
(DWORD_PTR)afxWndProc);
ASSERT(oldWndProc != NULL);
if (oldWndProc != afxWndProc)
*pOldWndProc = oldWndProc;
pThreadState->m_pWndInit = NULL;
}
else
{
ASSERT(!bContextIsDLL); // should never get here
static ATOM s_atomMenu = 0;
bool bSubclass = true;
if (s_atomMenu == 0)
{
WNDCLASSEX wc;
memset(&wc, 0, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
s_atomMenu = (ATOM)::AfxCtxGetClassInfoEx(NULL, _T("#32768"), &wc);
}
// Do not subclass menus.
if (s_atomMenu != 0)
{
ATOM atomWnd = (ATOM)::GetClassLongPtr(hWnd, GCW_ATOM);
if (atomWnd == s_atomMenu)
bSubclass = false;
}
else
{
TCHAR szClassName[256];
if (::GetClassName(hWnd, szClassName, 256))
{
szClassName[255] = NULL;
if (_tcscmp(szClassName, _T("#32768")) == 0)
bSubclass = false;
}
}
if (bSubclass)
{
// subclass the window with the proc which does gray backgrounds
oldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
if (oldWndProc != NULL && GetProp(hWnd, _afxOldWndProc) == NULL)
{
SetProp(hWnd, _afxOldWndProc, oldWndProc);
if ((WNDPROC)GetProp(hWnd, _afxOldWndProc) == oldWndProc)
{
GlobalAddAtom(_afxOldWndProc);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (DWORD_PTR)_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)(UINT_PTR)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)
{
ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
AfxIsValidAtom(lpszClassName));
ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
// 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 = ::AfxCtxCreateWindowEx(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)
{
TRACE(traceAppMsg, 0, "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)(UINT_PTR)nID, (LPVOID)pContext);
}
CWnd::~CWnd()
{
if (m_hWnd != NULL &&
this != (CWnd*)&wndTop && this != (CWnd*)&wndBottom &&
this != (CWnd*)&wndTopMost && this != (CWnd*)&wndNoTopMost)
{
TRACE(traceAppMsg, 0, _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
// Active Accessibility
if (m_pProxy != NULL)
m_pProxy->SetServer(NULL, NULL);
if (m_pStdObject != NULL)
m_pStdObject->Release();
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 = AfxGetModuleThreadState()->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_PTR)m_hWnd;
pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&ti);
}
}
// call default, unsubclass, and detach from the map
WNDPROC pfnWndProc = WNDPROC(GetWindowLongPtr(m_hWnd, GWLP_WNDPROC));
Default();
if (WNDPROC(GetWindowLongPtr(m_hWnd, GWLP_WNDPROC)) == pfnWndProc)
{
WNDPROC pfnSuper = *GetSuperWndProcAddr();
if (pfnSuper != NULL)
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, reinterpret_cast<INT_PTR>(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=NULL;
if(pMap)
{
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 = " << (void*)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*)(DWORD_PTR)::GetWindowLong(m_hWnd, GWL_STYLE);
if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_CHILD)
dc << "\nid = " << _AfxGetDlgCtrlID(m_hWnd);
dc << "\n";
}
#endif
BOOL CWnd::DestroyWindow()
{
CWnd* pWnd;
CHandleMap* pMap;
HWND hWndOrig;
BOOL bResult;
if ((m_hWnd == NULL) && (m_pCtrlSite == NULL))
return FALSE;
bResult = FALSE;
pMap = NULL;
pWnd = NULL;
hWndOrig = NULL;
if (m_hWnd != NULL)
{
pMap = afxMapHWND();
ENSURE(pMap != NULL);
pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
#ifdef _DEBUG
hWndOrig = m_hWnd;
#endif
}
#ifdef _AFX_NO_OCC_SUPPORT
if (m_hWnd != NULL)
bResult = ::DestroyWindow(m_hWnd);
#else //_AFX_NO_OCC_SUPPORT
if ((m_hWnd != NULL) || (m_pCtrlSite != NULL))
{
if (m_pCtrlSite == NULL)
bResult = ::DestroyWindow(m_hWnd);
else
bResult = m_pCtrlSite->DestroyControl();
}
#endif //_AFX_NO_OCC_SUPPORT
if (hWndOrig != NULL)
{
// 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_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();
CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip;
if (pToolTip->GetSafeHwnd() != NULL)
pToolTip->SendMessage(TTM_ACTIVATE, FALSE);
// check for active control bar fly-by status
CControlBar* pLastStatus = pModuleThreadState->m_pLastStatus;
if (bKeys && pLastStatus != NULL && GetKeyState(VK_LBUTTON) >= 0)
pLastStatus->SetStatusText(static_cast<INT_PTR>(-1));
}
INT_PTR 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_PTR 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_PTR)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 = _T(""); // 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 (int)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
}
}
// 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;
}
BOOL CMenu::TrackPopupMenuEx(UINT fuFlags, int x, int y, CWnd* pWnd, LPTPMPARAMS lptpm)
{
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 = ::TrackPopupMenuEx(m_hMenu, fuFlags, x, y,
pThreadState->m_hTrackingWindow, lptpm);
pThreadState->m_hTrackingWindow = hWndOld;
pThreadState->m_hTrackingMenu = hMenuOld;
return bOK;
}
AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ENSURE_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)
{
if(pPopup->m_hMenu == (HMENU)(UINT_PTR)nID) {
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// 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=NULL;
_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();
}
ENSURE(pMenu);
pMenu = _AfxFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if (pMenu != NULL)
{
pMenu->MeasureItem(lpMeasureItemStruct);
}
else
{
TRACE(traceAppMsg, 0, "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 (AfxCtxGetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
&wndcls))
{
// class already registered
return TRUE;
}
if (!::AfxCtxRegisterClass(lpWndClass))
{
TRACE(traceAppMsg, 0, _T("Can't register window class named %s\n"),
lpWndClass->lpszClassName);
return FALSE;
}
BOOL bRet = TRUE;
if (afxContextIsDLL)
{
AfxLockGlobals(CRIT_REGCLASSLIST);
TRY
{
// class registered successfully, add to registered list
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_strUnregisterList+=lpWndClass->lpszClassName;
pModuleState->m_strUnregisterList+='\n';
}
CATCH_ALL(e)
{
AfxUnlockGlobals(CRIT_REGCLASSLIST);
THROW_LAST();
// Note: DELETE_EXCEPTION not required.
}
END_CATCH_ALL
AfxUnlockGlobals(CRIT_REGCLASSLIST);
}
return bRet;
}
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)
{
ATL_CRT_ERRORCHECK_SPRINTF(_sntprintf_s(lpszName, _AFX_TEMP_CLASS_NAME_SIZE, _AFX_TEMP_CLASS_NAME_SIZE - 1, _T("Afx:%p:%x"), hInst, nClassStyle));
}
else
{
ATL_CRT_ERRORCHECK_SPRINTF(_sntprintf_s(lpszName, _AFX_TEMP_CLASS_NAME_SIZE, _AFX_TEMP_CLASS_NAME_SIZE - 1, _T("Afx:%p:%x:%p:%p:%p"), hInst, nClassStyle,
hCursor, hbrBackground, hIcon));
}
// see if the class already exists
WNDCLASS wndcls;
if (::AfxCtxGetClassInfo(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_PTR dwData, UINT nCmd)
{
CWinApp* pApp = AfxGetApp();
ASSERT_VALID(pApp);
ASSERT(pApp->m_pszHelpFilePath != NULL);
ASSERT(pApp->m_eHelpType == afxWinHelp);
CWaitCursor wait;
PrepareForHelp();
// need to use top level parent (for the case where m_hWnd is in DLL)
CWnd* pWnd = EnsureTopLevelParent();
TRACE(traceAppMsg, 0, _T("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);
}
}
void CWnd::HtmlHelp(DWORD_PTR dwData, UINT nCmd)
{
CWinApp* pApp = AfxGetApp();
ASSERT_VALID(pApp);
ASSERT(pApp->m_pszHelpFilePath != NULL);
// to call HtmlHelp the m_fUseHtmlHelp must be set in
// the application's constructor
ASSERT(pApp->m_eHelpType == afxHTMLHelp);
CWaitCursor wait;
PrepareForHelp();
// need to use top level parent (for the case where m_hWnd is in DLL)
CWnd* pWnd = EnsureTopLevelParent();
TRACE(traceAppMsg, 0, _T("HtmlHelp: pszHelpFile = '%s', dwData: $%lx, fuCommand: %d.\n"), pApp->m_pszHelpFilePath, dwData, nCmd);
// run the HTML Help engine
if (!AfxHtmlHelp(pWnd->m_hWnd, pApp->m_pszHelpFilePath, nCmd, dwData))
{
AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP);
}
}
void CWnd::PrepareForHelp()
{
if (IsFrameWnd())
{
// CFrameWnd windows should be allowed to exit help mode first
CFrameWnd* pFrameWnd = static_cast<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 = EnsureTopLevelParent();
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);
}
// for dll builds we just delay load it
#ifndef _AFXDLL
_AFX_HTMLHELP_STATE::~_AFX_HTMLHELP_STATE()
{
if (m_hInstHtmlHelp)
FreeLibrary(m_hInstHtmlHelp);
}
#endif
HWND WINAPI AfxHtmlHelp(HWND hWnd, LPCTSTR szHelpFilePath, UINT nCmd, DWORD_PTR dwData)
{
// for dll builds we just delay load it
#ifndef _AFXDLL
#ifdef _UNICODE
#define _HTMLHELP_ENTRY "HtmlHelpW"
#else
#define _HTMLHELP_ENTRY "HtmlHelpA"
#endif
AfxLockGlobals(CRIT_DYNDLLLOAD);
// check if the HtmlHelp library was loaded
_AFX_HTMLHELP_STATE* pState = _afxHtmlHelpState.GetData();
if (!pState->m_pfnHtmlHelp)
{
// load the library
ASSERT(!pState->m_hInstHtmlHelp);
pState->m_hInstHtmlHelp = AfxCtxLoadLibraryA("hhctrl.ocx");
if (!pState->m_hInstHtmlHelp)
return NULL;
pState->m_pfnHtmlHelp = (HTMLHELPPROC *) GetProcAddress(pState->m_hInstHtmlHelp, _HTMLHELP_ENTRY);
if (!pState->m_pfnHtmlHelp)
{
FreeLibrary(pState->m_hInstHtmlHelp);
pState->m_hInstHtmlHelp = NULL;
return NULL;
}
}
AfxUnlockGlobals(CRIT_DYNDLLLOAD);
// now call it
return (*(pState->m_pfnHtmlHelp))(hWnd, szHelpFilePath, nCmd, dwData);
#else
return ::HtmlHelp(hWnd, szHelpFilePath, nCmd, dwData);
#endif
}
void CWnd::WinHelpInternal(DWORD_PTR dwData, UINT nCmd)
{
CWinApp* pApp = AfxGetApp();
ASSERT_VALID(pApp);
if (pApp->m_eHelpType == afxHTMLHelp)
{
// translate from WinHelp commands and data to to HtmlHelp
ASSERT((nCmd == HELP_CONTEXT) || (nCmd == HELP_CONTENTS) || (nCmd == HELP_FINDER));
if (nCmd == HELP_CONTEXT)
nCmd = HH_HELP_CONTEXT;
else if (nCmd == HELP_CONTENTS)
nCmd = HH_DISPLAY_TOC;
else if (nCmd == HELP_FINDER)
nCmd = HH_HELP_FINDER;
HtmlHelp(dwData, nCmd);
}
else
WinHelp(dwData, nCmd);
}
/////////////////////////////////////////////////////////////////////////////
// Message table implementation
BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
ON_MESSAGE(WM_CTLCOLORSTATIC, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLOREDIT, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORBTN, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORLISTBOX, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORDLG, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORMSGBOX, &CWnd::OnNTCtlColor)
ON_MESSAGE(WM_CTLCOLORSCROLLBAR, &CWnd::OnNTCtlColor)
//{{AFX_MSG_MAP(CWnd)
ON_WM_SETFOCUS()
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, &CWnd::OnActivateTopLevel)
ON_MESSAGE(WM_DISPLAYCHANGE, &CWnd::OnDisplayChange)
ON_REGISTERED_MESSAGE(CWnd::m_nMsgDragList, &CWnd::OnDragList)
ON_MESSAGE(WM_GETOBJECT, &CWnd::OnGetObject)
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;
union MessageMapFunctions mmf;
mmf.pfn = 0;
CInternalGlobalLock winMsgLock;
// 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;
}
// special case for windows that contain windowless ActiveX controls
BOOL bHandled;
bHandled = FALSE;
if ((m_pCtrlCont != NULL) && (m_pCtrlCont->m_nWindowlessControls > 0))
{
if (((message >= WM_MOUSEFIRST) && (message <= AFX_WM_MOUSELAST)) ||
((message >= WM_KEYFIRST) && (message <= WM_IME_KEYLAST)) ||
((message >= WM_IME_SETCONTEXT) && (message <= WM_IME_KEYUP)))
{
bHandled = m_pCtrlCont->HandleWindowlessMessage(message, wParam, lParam, &lResult);
}
}
if (bHandled)
{
goto LReturnTrue;
}
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
UINT iHash; iHash = (LOWORD((DWORD_PTR)pMessageMap) ^ message) & (iHashMax-1);
winMsgLock.Lock(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;
winMsgLock.Unlock();
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;
for (/* pMessageMap already init'ed */; pMessageMap->pfnGetBaseMap != NULL;
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
{
// Note: catch not so common but fatal mistake!!
// BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
if (message < 0xC000)
{
// constant window message
if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
message, 0, 0)) != NULL)
{
pMsgCache->lpEntry = lpEntry;
winMsgLock.Unlock();
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;
winMsgLock.Unlock();
goto LDispatchRegistered;
}
lpEntry++; // keep looking past this one
}
}
}
pMsgCache->lpEntry = NULL;
winMsgLock.Unlock();
return FALSE;
}
LDispatch:
ASSERT(message < 0xC000);
mmf.pfn = lpEntry->pfn;
switch (lpEntry->nSig)
{
default:
ASSERT(FALSE);
break;
case AfxSig_l_p:
{
CPoint point(lParam);
lResult = (this->*mmf.pfn_l_p)(point);
break;
}
case AfxSig_b_D_v:
lResult = (this->*mmf.pfn_b_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
break;
case AfxSig_b_b_v:
lResult = (this->*mmf.pfn_b_b)(static_cast<BOOL>(wParam));
break;
case AfxSig_b_u_v:
lResult = (this->*mmf.pfn_b_u)(static_cast<UINT>(wParam));
break;
case AfxSig_b_h_v:
lResult = (this->*mmf.pfn_b_h)(reinterpret_cast<HANDLE>(wParam));
break;
case AfxSig_i_u_v:
lResult = (this->*mmf.pfn_i_u)(static_cast<UINT>(wParam));
break;
case AfxSig_C_v_v:
lResult = reinterpret_cast<LRESULT>((this->*mmf.pfn_C_v)());
break;
case AfxSig_v_u_W:
(this->*mmf.pfn_v_u_W)(static_cast<UINT>(wParam),
CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
break;
case AfxSig_u_u_v:
lResult = (this->*mmf.pfn_u_u)(static_cast<UINT>(wParam));
break;
case AfxSig_b_v_v:
lResult = (this->*mmf.pfn_b_v)();
break;
case AfxSig_b_W_uu:
lResult = (this->*mmf.pfn_b_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_b_W_COPYDATASTRUCT:
lResult = (this->*mmf.pfn_b_W_COPYDATASTRUCT)(
CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
reinterpret_cast<COPYDATASTRUCT*>(lParam));
break;
case AfxSig_b_v_HELPINFO:
lResult = (this->*mmf.pfn_b_HELPINFO)(reinterpret_cast<LPHELPINFO>(lParam));
break;
case AfxSig_CTLCOLOR:
{
// special case for OnCtlColor to avoid too many temporary objects
ASSERT(message == WM_CTLCOLOR);
AFX_CTLCOLOR* pCtl = reinterpret_cast<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_B_D_W_u)(&dcTemp, pWnd, nCtlType);
// fast detach of temporary objects
dcTemp.m_hDC = NULL;
wndTemp.m_hWnd = NULL;
lResult = reinterpret_cast<LRESULT>(hbr);
}
break;
case AfxSig_CTLCOLOR_REFLECT:
{
// special case for CtlColor to avoid too many temporary objects
ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
AFX_CTLCOLOR* pCtl = reinterpret_cast<AFX_CTLCOLOR*>(lParam);
CDC dcTemp;
dcTemp.m_hDC = pCtl->hDC;
UINT nCtlType = pCtl->nCtlType;
HBRUSH hbr = (this->*mmf.pfn_B_D_u)(&dcTemp, nCtlType);
// fast detach of temporary objects
dcTemp.m_hDC = NULL;
lResult = reinterpret_cast<LRESULT>(hbr);
}
break;
case AfxSig_i_u_W_u:
lResult = (this->*mmf.pfn_i_u_W_u)(LOWORD(wParam),
CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
break;
case AfxSig_i_uu_v:
lResult = (this->*mmf.pfn_i_u_u)(LOWORD(wParam), HIWORD(wParam));
break;
case AfxSig_i_W_uu:
lResult = (this->*mmf.pfn_i_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_i_v_s:
lResult = (this->*mmf.pfn_i_s)(reinterpret_cast<LPTSTR>(lParam));
break;
case AfxSig_l_w_l:
lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);
break;
case AfxSig_l_uu_M:
lResult = (this->*mmf.pfn_l_u_u_M)(LOWORD(wParam), HIWORD(wParam),
CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
break;
case AfxSig_v_b_h:
(this->*mmf.pfn_v_b_h)(static_cast<BOOL>(wParam),
reinterpret_cast<HANDLE>(lParam));
break;
case AfxSig_v_h_v:
(this->*mmf.pfn_v_h)(reinterpret_cast<HANDLE>(wParam));
break;
case AfxSig_v_h_h:
(this->*mmf.pfn_v_h_h)(reinterpret_cast<HANDLE>(wParam),
reinterpret_cast<HANDLE>(lParam));
break;
case AfxSig_v_v_v:
(this->*mmf.pfn_v_v)();
break;
case AfxSig_v_u_v:
(this->*mmf.pfn_v_u)(static_cast<UINT>(wParam));
break;
case AfxSig_v_u_u:
(this->*mmf.pfn_v_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
break;
case AfxSig_v_uu_v:
(this->*mmf.pfn_v_u_u)(LOWORD(wParam), HIWORD(wParam));
break;
case AfxSig_v_v_ii:
(this->*mmf.pfn_v_i_i)(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case AfxSig_v_u_uu:
(this->*mmf.pfn_v_u_u_u)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_v_u_ii:
(this->*mmf.pfn_v_u_i_i)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
break;
case AfxSig_v_w_l:
(this->*mmf.pfn_v_w_l)(wParam, lParam);
break;
case AfxSig_MDIACTIVATE:
(this->*mmf.pfn_v_b_W_W)(m_hWnd == reinterpret_cast<HWND>(lParam),
CWnd::FromHandle(reinterpret_cast<HWND>(lParam)),
CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
break;
case AfxSig_v_D_v:
(this->*mmf.pfn_v_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
break;
case AfxSig_v_M_v:
(this->*mmf.pfn_v_M)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)));
break;
case AfxSig_v_M_ub:
(this->*mmf.pfn_v_M_u_b)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)),
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case AfxSig_v_W_v:
(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
break;
case AfxSig_v_v_W:
(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
break;
case AfxSig_v_W_uu:
(this->*mmf.pfn_v_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), LOWORD(lParam),
HIWORD(lParam));
break;
case AfxSig_v_W_p:
{
CPoint point(lParam);
(this->*mmf.pfn_v_W_p)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), point);
}
break;
case AfxSig_v_W_h:
(this->*mmf.pfn_v_W_h)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
reinterpret_cast<HANDLE>(lParam));
break;
case AfxSig_ACTIVATE:
(this->*mmf.pfn_v_u_W_b)(LOWORD(wParam),
CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
break;
case AfxSig_SCROLL:
case AfxSig_SCROLL_REFLECT:
{
// 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_SCROLL)
(this->*mmf.pfn_v_u_u_W)(nScrollCode, nPos,
CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
else
(this->*mmf.pfn_v_u_u)(nScrollCode, nPos);
}
break;
case AfxSig_v_v_s:
(this->*mmf.pfn_v_s)(reinterpret_cast<LPTSTR>(lParam));
break;
case AfxSig_v_u_cs:
(this->*mmf.pfn_v_u_cs)(static_cast<UINT>(wParam), reinterpret_cast<LPCTSTR>(lParam));
break;
case AfxSig_OWNERDRAW:
(this->*mmf.pfn_v_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
lResult = TRUE;
break;
case AfxSig_i_i_s:
lResult = (this->*mmf.pfn_i_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
break;
case AfxSig_u_v_p:
{
CPoint point(lParam);
lResult = (this->*mmf.pfn_u_p)(point);
}
break;
case AfxSig_u_v_v:
lResult = (this->*mmf.pfn_u_v)();
break;
case AfxSig_v_b_NCCALCSIZEPARAMS:
(this->*mmf.pfn_v_b_NCCALCSIZEPARAMS)(static_cast<BOOL>(wParam),
reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam));
break;
case AfxSig_v_v_WINDOWPOS:
(this->*mmf.pfn_v_v_WINDOWPOS)(reinterpret_cast<WINDOWPOS*>(lParam));
break;
case AfxSig_v_uu_M:
(this->*mmf.pfn_v_u_u_M)(LOWORD(wParam), HIWORD(wParam), reinterpret_cast<HMENU>(lParam));
break;
case AfxSig_v_u_p:
{
CPoint point(lParam);
(this->*mmf.pfn_v_u_p)(static_cast<UINT>(wParam), point);
}
break;
case AfxSig_SIZING:
(this->*mmf.pfn_v_u_pr)(static_cast<UINT>(wParam), reinterpret_cast<LPRECT>(lParam));
lResult = TRUE;
break;
case AfxSig_MOUSEWHEEL:
lResult = (this->*mmf.pfn_b_u_s_p)(LOWORD(wParam), (short)HIWORD(wParam),
CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
if (!lResult)
return FALSE;
break;
case AfxSig_MOUSEHWHEEL:
(this->*mmf.pfn_MOUSEHWHEEL)(LOWORD(wParam), (short)HIWORD(wParam),
CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
case AfxSig_l:
lResult = (this->*mmf.pfn_l_v)();
if (lResult != 0)
return FALSE;
break;
case AfxSig_u_W_u:
lResult = (this->*mmf.pfn_u_W_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(lParam));
break;
case AfxSig_v_u_M:
(this->*mmf.pfn_v_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
break;
case AfxSig_u_u_M:
lResult = (this->*mmf.pfn_u_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
break;
case AfxSig_u_v_MENUGETOBJECTINFO:
lResult = (this->*mmf.pfn_u_v_MENUGETOBJECTINFO)(reinterpret_cast<MENUGETOBJECTINFO*>(lParam));
break;
case AfxSig_v_M_u:
(this->*mmf.pfn_v_M_u)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)), static_cast<UINT>(lParam));
break;
case AfxSig_v_u_LPMDINEXTMENU:
(this->*mmf.pfn_v_u_LPMDINEXTMENU)(static_cast<UINT>(wParam), reinterpret_cast<LPMDINEXTMENU>(lParam));
break;
case AfxSig_APPCOMMAND:
(this->*mmf.pfn_APPCOMMAND)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(GET_APPCOMMAND_LPARAM(lParam)), static_cast<UINT>(GET_DEVICE_LPARAM(lParam)), static_cast<UINT>(GET_KEYSTATE_LPARAM(lParam)));
lResult = TRUE;
break;
case AfxSig_RAWINPUT:
(this->*mmf.pfn_RAWINPUT)(static_cast<UINT>(GET_RAWINPUT_CODE_WPARAM(wParam)), reinterpret_cast<HRAWINPUT>(lParam));
break;
case AfxSig_u_u_u:
lResult = (this->*mmf.pfn_u_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
break;
case AfxSig_MOUSE_XBUTTON:
(this->*mmf.pfn_MOUSE_XBUTTON)(static_cast<UINT>(GET_KEYSTATE_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
lResult = TRUE;
break;
case AfxSig_MOUSE_NCXBUTTON:
(this->*mmf.pfn_MOUSE_NCXBUTTON)(static_cast<short>(GET_NCHITTEST_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
lResult = TRUE;
break;
case AfxSig_INPUTLANGCHANGE:
(this->*mmf.pfn_INPUTLANGCHANGE)(static_cast<BYTE>(wParam), static_cast<UINT>(lParam));
lResult = TRUE;
break;
case AfxSig_INPUTDEVICECHANGE:
(this->*mmf.pfn_INPUTDEVICECHANGE)(GET_DEVICE_CHANGE_LPARAM(wParam));
break;
case AfxSig_v_u_hkl:
(this->*mmf.pfn_v_u_h)(static_cast<UINT>(wParam), reinterpret_cast<HKL>(lParam));
break;
}
goto LReturnTrue;
LDispatchRegistered: // for registered windows messages
ASSERT(message >= 0xC000);
ASSERT(sizeof(mmf) == sizeof(mmf.pfn));
mmf.pfn = lpEntry->pfn;
lResult = (this->*mmf.pfn_l_w_l)(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)
{
TRACE(traceAppMsg, 0, "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)
TRACE(traceAppMsg, 0, "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_PTR 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((UINT)nID, MAKELONG(nCode, WM_NOTIFY), &notify, 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);
CWnd *pWndTopLevel=EnsureTopLevelParent();
return CWnd::GetForegroundWindow() == pWndTopLevel->GetLastActivePopup();
}
void CWnd::ActivateTopParent()
{
// special activate logic for floating toolbars and palettes
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.
EnsureTopLevelParent()->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 = ::AfxCtxMessageBox(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);
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);
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 & ~reposNoPosLeftOver) == reposQuery ||
(nFlags & ~reposNoPosLeftOver) == 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 & ~reposNoPosLeftOver) != 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_PTR 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 & ~reposNoPosLeftOver) == 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 & ~reposNoPosLeftOver) == 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
if ((nFlags & reposNoPosLeftOver) != reposNoPosLeftOver)
{
pLeftOver->CalcWindowRect(&layout.rect);
AfxRepositionWindow(&layout, hWndLeftOver, &layout.rect);
}
}
// move and resize all the windows at once!
if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
TRACE(traceAppMsg, 0, "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 != 0;
}
}
#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), &notify, 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();
}
void CWnd::OnSetFocus(CWnd*)
{
BOOL bHandled;
bHandled = FALSE;
#ifndef _AFX_NO_OCC_SUPPORT
if (m_pCtrlCont != NULL)
{
bHandled = m_pCtrlCont->HandleSetFocus();
}
#endif //!_AFX_NO_OCC_SUPPORT
if( !bHandled )
{
Default();
}
}
LRESULT CWnd::OnActivateTopLevel(WPARAM wParam, LPARAM)
{
if (LOWORD(wParam) == WA_INACTIVE)
{
AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();
if (pModuleThreadState->m_pLastInfo != NULL &&
!(pModuleThreadState->m_pLastInfo->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();
}
// 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);
// force refresh of settings that we cache
_afxGotScrollLines = FALSE;
if (m_pCtrlCont != NULL)
{
m_pCtrlCont->BroadcastAmbientPropertyChange( DISPID_AMBIENT_LOCALEID );
}
CWnd::OnDisplayChange(0, 0); // to update system metrics, etc.
}
void CWnd::OnDevModeChange(_In_z_ 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() != 0;
}
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();
}
// Accessibility
LRESULT CWnd::OnGetObject(WPARAM wParam, LPARAM lParam)
{
if (!m_bEnableActiveAccessibility)
return Default();
LRESULT lRet = 0;
HRESULT hr = CreateAccessibleProxy(wParam, lParam, &lRet);
if (FAILED(hr))
return Default();
return lRet;
}
//Helper class for Active Accesibility Proxy
//Base is the user's class that derives from CComObjectRoot and whatever
//interfaces the user wants to support on the object
void AFXAPI AfxOleLockApp();
void AFXAPI AfxOleUnlockApp();
template <class Base>
class CMFCComObject : public Base
{
public:
typedef Base _BaseClass;
CMFCComObject(void* = NULL)
{
AfxOleLockApp();
}
// Set refcount to -(LONG_MAX/2) to protect destruction and
// also catch mismatched Release in debug builds
~CMFCComObject()
{
m_dwRef = -(LONG_MAX/2);
FinalRelease();
#ifdef _ATL_DEBUG_INTERFACES
_AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
#endif
AfxOleUnlockApp();
}
//If InternalAddRef or InternalRelease is undefined then your class
//doesn't derive from CComObjectRoot
STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();}
STDMETHOD_(ULONG, Release)() throw()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
{return _InternalQueryInterface(iid, ppvObject);}
template <class Q>
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
{
return QueryInterface(__uuidof(Q), (void**)pp);
}
static HRESULT WINAPI CreateInstance(CMFCComObject<Base>** pp)
{
ATLASSERT(pp != NULL);
if (pp == NULL)
return E_POINTER;
*pp = NULL;
HRESULT hRes = E_OUTOFMEMORY;
CMFCComObject<Base>* p = NULL;
ATLTRY(p = new CMFCComObject<Base>())
if (p != NULL)
{
p->SetVoid(NULL);
p->InternalFinalConstructAddRef();
hRes = p->_AtlInitialConstruct();
if (SUCCEEDED(hRes))
hRes = p->FinalConstruct();
if (SUCCEEDED(hRes))
hRes = p->_AtlFinalConstruct();
p->InternalFinalConstructRelease();
if (hRes != S_OK)
{
delete p;
p = NULL;
}
}
*pp = p;
return hRes;
}
};
BEGIN_INTERFACE_MAP(CWnd, CCmdTarget)
// INTERFACE_PART(CWnd, __uuidof(IAccessible), Accessible)
// INTERFACE_PART(CWnd, __uuidof(IAccessibleServer), AccessibleServer)
END_INTERFACE_MAP()
ULONG FAR EXPORT CWnd::XAccessible::AddRef()
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CWnd::XAccessible::Release()
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CWnd::XAccessible::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CWnd, Accessible)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
HRESULT CWnd::XAccessible::Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID refiid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr)
{
METHOD_PROLOGUE(CWnd, Accessible)
return AtlIAccessibleInvokeHelper((IAccessible*)(void*)this, dispIdMember, refiid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
HRESULT CWnd::XAccessible::GetIDsOfNames(
REFIID refiid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId)
{
return AtlIAccessibleGetIDsOfNamesHelper(refiid, rgszNames, cNames, lcid, rgDispId);
}
HRESULT CWnd::XAccessible::GetTypeInfoCount(unsigned int* pctinfo)
{
if (pctinfo == NULL)
{
return E_POINTER;
}
*pctinfo = 1;
return S_OK;
}
HRESULT CWnd::XAccessible::GetTypeInfo(unsigned int /*iTInfo*/, LCID /*lcid*/, ITypeInfo** /*ppTInfo*/)
{
return E_NOTIMPL;
}
HRESULT CWnd::XAccessible::get_accParent(IDispatch **ppdispParent)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accParent(ppdispParent);
}
HRESULT CWnd::XAccessible::get_accChildCount(long *pcountChildren)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accChildCount(pcountChildren);
}
HRESULT CWnd::XAccessible::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accChild(varChild, ppdispChild);
}
HRESULT CWnd::XAccessible::get_accName(VARIANT varChild, BSTR *pszName)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accName(varChild, pszName);
}
HRESULT CWnd::XAccessible::get_accValue(VARIANT varChild, BSTR *pszValue)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accValue(varChild, pszValue);
}
HRESULT CWnd::XAccessible::get_accDescription(VARIANT varChild, BSTR *pszDescription)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accDescription(varChild, pszDescription);
}
HRESULT CWnd::XAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accRole(varChild, pvarRole);
}
HRESULT CWnd::XAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accState(varChild, pvarState);
}
HRESULT CWnd::XAccessible::get_accHelp(VARIANT varChild, BSTR *pszHelp)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accHelp(varChild, pszHelp);
}
HRESULT CWnd::XAccessible::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accHelpTopic(pszHelpFile, varChild, pidTopic);
}
HRESULT CWnd::XAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
}
HRESULT CWnd::XAccessible::get_accFocus(VARIANT *pvarChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accFocus(pvarChild);
}
HRESULT CWnd::XAccessible::get_accSelection(VARIANT *pvarChildren)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accSelection(pvarChildren);
}
HRESULT CWnd::XAccessible::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->get_accDefaultAction(varChild, pszDefaultAction);
}
HRESULT CWnd::XAccessible::accSelect(long flagsSelect, VARIANT varChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->accSelect(flagsSelect, varChild);
}
HRESULT CWnd::XAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
}
HRESULT CWnd::XAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->accNavigate(navDir, varStart, pvarEndUpAt);
}
HRESULT CWnd::XAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->accHitTest(xLeft, yTop, pvarChild);
}
HRESULT CWnd::XAccessible::accDoDefaultAction(VARIANT varChild)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->accDoDefaultAction(varChild);
}
//Obsolete
HRESULT CWnd::XAccessible::put_accName(VARIANT varChild, BSTR szName)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->put_accName(varChild, szName);
}
//Obsolete
HRESULT CWnd::XAccessible::put_accValue(VARIANT varChild, BSTR szValue)
{
METHOD_PROLOGUE(CWnd, Accessible)
return pThis->put_accValue(varChild, szValue);
}
ULONG FAR EXPORT CWnd::XAccessibleServer::AddRef()
{
METHOD_PROLOGUE(CWnd, AccessibleServer)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CWnd::XAccessibleServer::Release()
{
METHOD_PROLOGUE(CWnd, AccessibleServer)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CWnd::XAccessibleServer::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CWnd, AccessibleServer)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
HRESULT CWnd::XAccessibleServer::SetProxy(IAccessibleProxy *pProxy)
{
METHOD_PROLOGUE(CWnd, AccessibleServer)
return pThis->SetProxy(pProxy);
}
HRESULT CWnd::XAccessibleServer::GetHWND(HWND *phWnd)
{
if (phWnd == NULL)
return E_POINTER;
METHOD_PROLOGUE(CWnd, AccessibleServer)
*phWnd = pThis->m_hWnd;
return S_OK;
}
HRESULT CWnd::XAccessibleServer::GetEnumVariant(IEnumVARIANT **ppEnumVariant)
{
if (ppEnumVariant == NULL)
return E_POINTER;
*ppEnumVariant = NULL;
return E_NOTIMPL;
}
HRESULT CWnd::EnsureStdObj()
{
if (m_pStdObject == NULL)
{
HRESULT hr = CreateStdAccessibleObject(m_hWnd, OBJID_CLIENT, __uuidof(IAccessible), (void**)&m_pStdObject);
if (FAILED(hr))
return hr;
}
return S_OK;
}
// Delegate to standard helper?
HRESULT CWnd::get_accParent(IDispatch **ppdispParent)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accParent(ppdispParent);
}
// Delegate to standard helper?
HRESULT CWnd::get_accChildCount(long *pcountChildren)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accChildCount(pcountChildren);
}
// Delegate to standard helper?
HRESULT CWnd::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accChild(varChild, ppdispChild);
}
// Override in users code
HRESULT CWnd::get_accName(VARIANT varChild, BSTR *pszName)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accName(varChild, pszName);
}
// Override in users code
// Default inplementation will get window text and return it.
HRESULT CWnd::get_accValue(VARIANT varChild, BSTR *pszValue)
{
return m_pStdObject->get_accValue(varChild, pszValue);
}
// Override in users code
HRESULT CWnd::get_accDescription(VARIANT varChild, BSTR *pszDescription)
{
return m_pStdObject->get_accDescription(varChild, pszDescription);
}
// Investigate
HRESULT CWnd::get_accRole(VARIANT varChild, VARIANT *pvarRole)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accRole(varChild, pvarRole);
}
// Investigate
HRESULT CWnd::get_accState(VARIANT varChild, VARIANT *pvarState)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accState(varChild, pvarState);
}
// Override in User's code?
HRESULT CWnd::get_accHelp(VARIANT varChild, BSTR *pszHelp)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accHelp(varChild, pszHelp);
}
// Override in user's code?
HRESULT CWnd::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accHelpTopic(pszHelpFile, varChild, pidTopic);
}
// Override in user's code?
HRESULT CWnd::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
}
// Delegate to standard implementation?
HRESULT CWnd::get_accFocus(VARIANT *pvarChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accFocus(pvarChild);
}
// Investigate
HRESULT CWnd::get_accSelection(VARIANT *pvarChildren)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accSelection(pvarChildren);
}
// Override in user's code
HRESULT CWnd::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->get_accDefaultAction(varChild, pszDefaultAction);
}
// Investigate
HRESULT CWnd::accSelect(long flagsSelect, VARIANT varChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->accSelect(flagsSelect, varChild);
}
// Delegate?
HRESULT CWnd::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
}
// Delegate? May have to implement for COM children
HRESULT CWnd::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->accNavigate(navDir, varStart, pvarEndUpAt);
}
// Delegate?
HRESULT CWnd::accHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->accHitTest(xLeft, yTop, pvarChild);
}
// Override in user's code
HRESULT CWnd::accDoDefaultAction(VARIANT varChild)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->accDoDefaultAction(varChild);
}
//Obsolete
HRESULT CWnd::put_accName(VARIANT varChild, BSTR szName)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->put_accName(varChild, szName);
}
//Obsolete
HRESULT CWnd::put_accValue(VARIANT varChild, BSTR szValue)
{
ASSERT(m_pStdObject != NULL);
return m_pStdObject->put_accName(varChild, szValue);
}
HRESULT CWnd::SetProxy(IAccessibleProxy *pProxy)
{
m_pProxy = pProxy;
return S_OK;
}
HRESULT CWnd::CreateAccessibleProxy(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
ASSERT(pResult != NULL);
DWORD dwObjId = (DWORD) lParam;
HRESULT hr = E_FAIL;
if (dwObjId == OBJID_CLIENT)
{
hr = EnsureStdObj();
if (SUCCEEDED(hr))
{
if (m_pProxy == NULL)
{
CMFCComObject<CAccessibleProxy> *p;
hr = CMFCComObject<CAccessibleProxy>::CreateInstance(&p);
if (SUCCEEDED(hr))
{
CComPtr<IAccessibleProxy> spProx;
hr = p->QueryInterface(&spProx);
if (SUCCEEDED(hr))
{
m_pProxy = spProx;
spProx->SetServer(static_cast<IAccessible*>((void*)&m_xAccessible), static_cast<IAccessibleServer*>((void*)&m_xAccessibleServer));
*pResult = LresultFromObject (__uuidof(IAccessible), wParam, m_pProxy);
}
hr = S_OK;
}
}
else
{
*pResult = LresultFromObject (__uuidof(IAccessible), wParam, m_pProxy);
hr = S_OK;
}
}
}
return hr;
}
// Helpers for CWnd or derived class that contains Windowless Active X controls
// Used by CView, CFormView, CDialog and CDialogBar
long CWnd::GetWindowLessChildCount()
{
long lCount = 0;
if (m_pCtrlCont != NULL)
{
// Add to the count the number of windowless active X controls.
POSITION pos = m_pCtrlCont->m_listSitesOrWnds.GetHeadPosition();
while(pos)
{
COleControlSiteOrWnd *pSiteOrWnd = m_pCtrlCont->m_listSitesOrWnds.GetNext(pos);
ASSERT(pSiteOrWnd);
if(pSiteOrWnd->m_pSite && pSiteOrWnd->m_pSite->m_bIsWindowless)
lCount ++;
}
}
return lCount;
}
long CWnd::GetWindowedChildCount()
{
long lCount = 0;
for (CWnd* pChild = GetWindow(GW_CHILD); pChild != NULL; pChild = pChild->GetWindow(GW_HWNDNEXT), lCount++);
return lCount;
}
long CWnd::GetAccessibleChildCount()
{
return GetWindowedChildCount() + GetWindowLessChildCount();
}
HRESULT CWnd::GetAccessibleChild(VARIANT varChild, IDispatch** ppdispChild)
{
if (ppdispChild == NULL)
return E_POINTER;
*ppdispChild = NULL;
long lCount = varChild.lVal - 1;
if (lCount < 0)
return E_INVALIDARG;
CWnd* pChild = NULL;
for(pChild = GetWindow(GW_CHILD); pChild != NULL && lCount != 0; pChild = pChild->GetWindow(GW_HWNDNEXT), lCount--);
if (pChild != NULL)
{
// Found HWND
return AccessibleObjectFromWindow(pChild->m_hWnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispChild);
}
// Windowless controls don't support accessibility.
return S_FALSE;
}
HRESULT CWnd::GetAccessibleName(VARIANT varChild, BSTR* pszName)
{
if (varChild.lVal == CHILDID_SELF)
{
CString strText;
GetWindowText(strText);
*pszName = strText.AllocSysString();
return S_OK;
}
else
{
// Get Number of windowed children
long lCount = GetWindowedChildCount();
if (varChild.lVal > lCount)
{
if (m_pCtrlCont != NULL)
{
// Add to the count the number of windowless active X controls.
POSITION pos = m_pCtrlCont->m_listSitesOrWnds.GetHeadPosition();
while(pos != NULL)
{
COleControlSiteOrWnd *pSiteOrWnd = m_pCtrlCont->m_listSitesOrWnds.GetNext(pos);
ASSERT(pSiteOrWnd);
if(pSiteOrWnd->m_pSite && pSiteOrWnd->m_pSite->m_bIsWindowless)
{
lCount ++;
if (lCount == varChild.lVal)
{
CString strText;
pSiteOrWnd->m_pSite->GetWindowText(strText);
*pszName = strText.AllocSysString();
return S_OK;
}
}
}
}
}
}
//out of range
return E_INVALIDARG;
}
HRESULT CWnd::GetAccessibilityLocation(VARIANT varChild, long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight)
{
HRESULT hr = CWnd::accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
if (FAILED(hr))
{
// Get Number of windowed children
long lCount;
CWnd::get_accChildCount(&lCount);
long lWindowlessCount = GetWindowLessChildCount();
if (varChild.lVal <= lCount + lWindowlessCount)
{
// Add to the count the number of windowless active X controls.
POSITION pos;
pos = m_pCtrlCont->m_listSitesOrWnds.GetHeadPosition();
COleControlSiteOrWnd *pSiteOrWnd;
while(pos)
{
pSiteOrWnd = m_pCtrlCont->m_listSitesOrWnds.GetNext(pos);
ASSERT(pSiteOrWnd);
if(pSiteOrWnd->m_pSite)
{
if(pSiteOrWnd->m_pSite->m_bIsWindowless)
lCount++;
if (lCount == varChild.lVal)
{
CRect rect(pSiteOrWnd->m_pSite->m_rect);
ClientToScreen(&rect);
*pxLeft = rect.left;
*pyTop = rect.top;
*pcxWidth = rect.Width();
*pcyHeight = rect.Height();
hr = S_OK;
}
}
}
}
}
return hr;
}
HRESULT CWnd::GetAccessibilityHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{
// Check if it is one of the Windowless controls
if (m_pCtrlCont != NULL)
{
CPoint pt(xLeft, yTop);
ScreenToClient(&pt);
long lCount = GetWindowedChildCount();
// If windowed child then let the standard object handle it.
if (m_pCtrlCont != NULL)
{
POSITION pos;
pos = m_pCtrlCont->m_listSitesOrWnds.GetHeadPosition();
while(pos)
{
COleControlSiteOrWnd *pSiteOrWnd = m_pCtrlCont->m_listSitesOrWnds.GetNext(pos);
ASSERT(pSiteOrWnd);
if (pSiteOrWnd->m_pSite && pSiteOrWnd->m_pSite->m_bIsWindowless)
{
lCount ++;
if (pSiteOrWnd->m_pSite->m_rect.PtInRect(pt))
{
pvarChild->vt = VT_I4;
pvarChild->lVal = lCount;
return S_OK;
}
}
}
}
}
return CWnd::accHitTest(xLeft, yTop, pvarChild);
}
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::OnPaint()
{
if (m_pCtrlCont != NULL)
{
// Paint windowless controls
CPaintDC dc(this);
m_pCtrlCont->OnPaint(&dc);
}
Default();
}
void CWnd::OnEnterIdle(UINT /*nWhy*/, CWnd* /*pWho*/)
{
// 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();
}
// 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.
TRACE(traceAppMsg, 0, "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;
}
/////////////////////////////////////////////////////////////////////////////
// '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_idLastControl = 0;
}
/////////////////////////////////////////////////////////////////////////////
// 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 dwAlternateStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
if (!(dwAlternateStyle & WS_VISIBLE) || (dwAlternateStyle & 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 + rcDlg.Width() > rcArea.right)
xLeft = rcArea.right - rcDlg.Width();
if (xLeft < rcArea.left)
xLeft = rcArea.left;
if (yTop + rcDlg.Height() > rcArea.bottom)
yTop = rcArea.bottom - rcDlg.Height();
if (yTop < rcArea.top)
yTop = rcArea.top;
// 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)
{
COMBOBOXEXITEM item = {0};
item.mask = CBEIF_TEXT;
item.iItem = -1;
CString strText(reinterpret_cast<LPTSTR>(lpnRes));
item.pszText = const_cast<LPTSTR>(strText.GetString());
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(0xffff,
WM_COMMAND+WM_REFLECT_BASE), &state, NULL))
continue;
}
// check for handlers in the parent window
if (CWnd::OnCmdMsg((UINT)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 > AFX_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 = AfxGetCurrentMessage();
// 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 (!AfxPumpMessage())
{
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 (AfxIsIdleMessage(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;
}
_AFX_OCC_DIALOG_INFO* CWnd::GetOccDialogInfo()
{
return NULL;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Standard init called by WinMain
AFX_STATIC BOOL AFXAPI _AfxRegisterWithIcon(WNDCLASS* pWndCls,
LPCTSTR lpszClassName, UINT nIDIcon)
{
pWndCls->lpszClassName = lpszClassName;
HINSTANCE hInst = AfxFindResourceHandle(
ATL_MAKEINTRESOURCE(nIDIcon), ATL_RT_GROUP_ICON);
if ((pWndCls->hIcon = ::LoadIcon(hInst, ATL_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);
LONG lResult = 0;
if (AFX_COMCTL32_IF_EXISTS(InitCommonControlsEx))
{
if (AfxInitCommonControlsEx(lpInitCtrls))
{
// InitCommonControlsEx was successful so return the full mask
lResult = fToRegister;
}
}
else
{
// not there, so call InitCommonControls if possible
if ((fToRegister & AFX_WIN95CTLS_MASK) == fToRegister)
{
AfxInitCommonControls();
lResult = AFX_WIN95CTLS_MASK;
}
}
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);
}
if (fToRegister & AFX_WNDCOMMCTL_LINK_REG)
{
init.dwICC = ICC_LINK_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LINK_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_PAGER_REG)
{
init.dwICC = ICC_PAGESCROLLER_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PAGER_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;
}
BOOL AFXAPI AfxInitNetworkAddressControl()
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
ENSURE(pModuleState);
if (pModuleState->m_bInitNetworkAddressControlCalled == FALSE)
{
OSVERSIONINFO vi;
ZeroMemory(&vi, sizeof(OSVERSIONINFO));
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
BOOL b = ::GetVersionEx(&vi);
ENSURE(b);
// if running under Vista
if (vi.dwMajorVersion >= 6)
{
// Only try to GetProcAddress and call InitNetworkAddressControl if we are vista and higher.
// If we call this on OS lower than Vista, this will throw. We don't want it to throw.
pModuleState->m_bInitNetworkAddressControl = AfxCtxInitNetworkAddressControl();
}
pModuleState->m_bInitNetworkAddressControlCalled = TRUE;
}
return pModuleState->m_bInitNetworkAddressControl;
}
/////////////////////////////////////////////////////////////////////////////
// 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;
}
/////////////////////////////////////////////////////////////////////////////
// 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)::SetWindowLongPtr(hWnd, GWLP_WNDPROC,
(INT_PTR)AfxGetAfxWndProc());
ASSERT(oldWndProc != AfxGetAfxWndProc());
if (*lplpfn == NULL)
*lplpfn = oldWndProc; // the first control of that type created
#ifdef _DEBUG
else if (*lplpfn != oldWndProc)
{
TRACE(traceAppMsg, 0, "Error: Trying to use SubclassWindow with incorrect CWnd\n");
TRACE(traceAppMsg, 0, "\tderived class.\n");
TRACE(traceAppMsg, 0, "\thWnd = $%08X (nIDC=$%08X) is not a %hs.\n", (UINT)(UINT_PTR)hWnd,
_AfxGetDlgCtrlID(hWnd), GetRuntimeClass()->m_lpszClassName);
ASSERT(FALSE);
// undo the subclassing if continuing after assert
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (INT_PTR)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();
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (INT_PTR)*lplpfn);
*lplpfn = NULL;
// and Detach the HWND from the CWnd object
return Detach();
}
BOOL CWnd::CreateControlContainer(COleControlContainer** ppContainer)
{
ENSURE_ARG( ppContainer != NULL );
*ppContainer = NULL; // Use the default container
return TRUE;
}
BOOL CWnd::CreateControlSite(COleControlContainer*,
COleControlSite** ppSite, UINT /* nID */, REFCLSID /* clsid */)
{
ENSURE_ARG( ppSite != NULL );
*ppSite = NULL; // Use the default site
return TRUE;
}
COleControlContainer* CWnd::GetControlContainer()
{
return m_pCtrlCont;
}
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment