// This is a part of the Active Template Library.
// Copyright (C) 1996-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.

#ifndef __ATLWIN_H__
#define __ATLWIN_H__

#ifndef __cplusplus
        #error ATL requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLBASE_H__
        #error atlwin.h requires atlbase.h to be included first
#endif

struct _ATL_WNDCLASSINFOA;
struct _ATL_WNDCLASSINFOW;


#ifndef _ATL_DLL_IMPL
namespace ATL
{
#endif

ATLAPI_(ATOM) AtlModuleRegisterWndClassInfoA(_ATL_MODULE* pM, _ATL_WNDCLASSINFOA* p, WNDPROC* pProc);
ATLAPI_(ATOM) AtlModuleRegisterWndClassInfoW(_ATL_MODULE* pM, _ATL_WNDCLASSINFOW* p, WNDPROC* pProc);

#ifdef UNICODE
#define AtlModuleRegisterWndClassInfo AtlModuleRegisterWndClassInfoW
#else
#define AtlModuleRegisterWndClassInfo AtlModuleRegisterWndClassInfoA
#endif


#define HIMETRIC_PER_INCH   2540
#define MAP_PIX_TO_LOGHIM(x,ppli)   ( (HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli) )
#define MAP_LOGHIM_TO_PIX(x,ppli)   ( ((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH )

ATLAPI_(HDC) AtlCreateTargetDC(HDC hdc, DVTARGETDEVICE* ptd);
ATLAPI_(void) AtlHiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix);
ATLAPI_(void) AtlPixelToHiMetric(const SIZEL * lpSizeInPix, LPSIZEL lpSizeInHiMetric);


#ifndef _ATL_DLL_IMPL
}; //namespace ATL
#endif

struct _ATL_WNDCLASSINFOA
{
        WNDCLASSEXA m_wc;
        LPCSTR m_lpszOrigName;
        WNDPROC pWndProc;
        LPCSTR m_lpszCursorID;
        BOOL m_bSystemCursor;
        ATOM m_atom;
    CHAR m_szAutoName[sizeof("ATL:") + (sizeof(PVOID)*2)+1];
        ATOM Register(WNDPROC* p)
        {
                return AtlModuleRegisterWndClassInfoA(&_Module, this, p);
        }
};
struct _ATL_WNDCLASSINFOW
{
        WNDCLASSEXW m_wc;
        LPCWSTR m_lpszOrigName;
        WNDPROC pWndProc;
        LPCWSTR m_lpszCursorID;
        BOOL m_bSystemCursor;
        ATOM m_atom;
    WCHAR m_szAutoName[sizeof("ATL:") + (sizeof(PVOID)*2)+1];
        ATOM Register(WNDPROC* p)
        {
                return AtlModuleRegisterWndClassInfoW(&_Module, this, p);
        }
};

namespace ATL
{

/////////////////////////////////////////////////////////////////////////////
// Forward declarations

class CWindow;
#ifndef _ATL_NO_HOSTING
template <class TBase = CWindow> class CAxWindowT;
#endif //!_ATL_NO_HOSTING
class CMessageMap;
class CDynamicChain;
typedef _ATL_WNDCLASSINFOA CWndClassInfoA;
typedef _ATL_WNDCLASSINFOW CWndClassInfoW;
#ifdef UNICODE
#define CWndClassInfo CWndClassInfoW
#else
#define CWndClassInfo CWndClassInfoA
#endif
template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CWindowImpl;
template <class T, class TBase = CWindow> class CDialogImpl;
#ifndef _ATL_NO_HOSTING
template <class T, class TBase = CWindow> class CAxDialogImpl;
#endif //!_ATL_NO_HOSTING
template <WORD t_wDlgTemplateID, BOOL t_bCenter = TRUE> class CSimpleDialog;
template <class TBase = CWindow, class TWinTraits = CControlWinTraits> class CContainedWindowT;

/////////////////////////////////////////////////////////////////////////////
// CWindow - client side for a Windows window

class CWindow
{
public:
        static RECT rcDefault;
        HWND m_hWnd;

        CWindow(HWND hWnd = NULL)
        {
                m_hWnd = hWnd;
        }

        CWindow& operator=(HWND hWnd)
        {
                m_hWnd = hWnd;
                return *this;
        }

        static LPCTSTR GetWndClassName()
        {
                return NULL;
        }

        void Attach(HWND hWndNew)
        {
                ATLASSERT(::IsWindow(hWndNew));
                m_hWnd = hWndNew;
        }

        HWND Detach()
        {
                HWND hWnd = m_hWnd;
                m_hWnd = NULL;
                return hWnd;
        }

        HWND Create(LPCTSTR lpstrWndClass, HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
                        DWORD dwStyle = 0, DWORD dwExStyle = 0,
                        UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                m_hWnd = ::CreateWindowEx(dwExStyle, lpstrWndClass, szWindowName,
                        dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
                        rcPos.bottom - rcPos.top, hWndParent, (HMENU)(DWORD_PTR)nID,
                        _Module.GetModuleInstance(), lpCreateParam);
                return m_hWnd;
        }

        HWND Create(LPCTSTR lpstrWndClass, HWND hWndParent, LPRECT lpRect = NULL, LPCTSTR szWindowName = NULL,
                        DWORD dwStyle = 0, DWORD dwExStyle = 0,
                        HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
        {
                if(lpRect == NULL)
                        lpRect = &rcDefault;
                m_hWnd = ::CreateWindowEx(dwExStyle, lpstrWndClass, szWindowName,
                        dwStyle, lpRect->left, lpRect->top, lpRect->right - lpRect->left,
                        lpRect->bottom - lpRect->top, hWndParent, hMenu,
                        _Module.GetModuleInstance(), lpCreateParam);
                return m_hWnd;
        }

        BOOL DestroyWindow()
        {
                ATLASSERT(::IsWindow(m_hWnd));

                if(!::DestroyWindow(m_hWnd))
                        return FALSE;

                m_hWnd = NULL;
                return TRUE;
        }

// Attributes

        operator HWND() const { return m_hWnd; }

        DWORD GetStyle() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (DWORD)::GetWindowLong(m_hWnd, GWL_STYLE);
        }

        DWORD GetExStyle() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (DWORD)::GetWindowLong(m_hWnd, GWL_EXSTYLE);
        }

        LONG GetWindowLong(int nIndex) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowLong(m_hWnd, nIndex);
        }

        LONG SetWindowLong(int nIndex, LONG dwNewLong)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowLong(m_hWnd, nIndex, dwNewLong);
        }

        WORD GetWindowWord(int nIndex) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowWord(m_hWnd, nIndex);
        }

        WORD SetWindowWord(int nIndex, WORD wNewWord)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowWord(m_hWnd, nIndex, wNewWord);
        }

// Message Functions

        LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SendMessage(m_hWnd,message,wParam,lParam);
        }

        BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::PostMessage(m_hWnd,message,wParam,lParam);
        }

        BOOL SendNotifyMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SendNotifyMessage(m_hWnd, message, wParam, lParam);
        }

        // support for C style macros
        static LRESULT SendMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
        {
                ATLASSERT(::IsWindow(hWnd));
                return ::SendMessage(hWnd, message, wParam, lParam);
        }

// Window Text Functions

        BOOL SetWindowText(LPCTSTR lpszString)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowText(m_hWnd, lpszString);
        }

        int GetWindowText(LPTSTR lpszStringBuf, int nMaxCount) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowText(m_hWnd, lpszStringBuf, nMaxCount);
        }

        int GetWindowTextLength() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowTextLength(m_hWnd);
        }

// Font Functions

        void SetFont(HFONT hFont, BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0));
        }

        HFONT GetFont() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (HFONT)::SendMessage(m_hWnd, WM_GETFONT, 0, 0);
        }

// Menu Functions (non-child windows only)

        HMENU GetMenu() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetMenu(m_hWnd);
        }

        BOOL SetMenu(HMENU hMenu)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetMenu(m_hWnd, hMenu);
        }

        BOOL DrawMenuBar()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DrawMenuBar(m_hWnd);
        }

        HMENU GetSystemMenu(BOOL bRevert) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetSystemMenu(m_hWnd, bRevert);
        }

        BOOL HiliteMenuItem(HMENU hMenu, UINT uItemHilite, UINT uHilite)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::HiliteMenuItem(m_hWnd, hMenu, uItemHilite, uHilite);
        }

// Window Size and Position Functions

        BOOL IsIconic() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsIconic(m_hWnd);
        }

        BOOL IsZoomed() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsZoomed(m_hWnd);
        }

        BOOL MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint);
        }

        BOOL MoveWindow(LPCRECT lpRect, BOOL bRepaint = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::MoveWindow(m_hWnd, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, bRepaint);
        }

        BOOL SetWindowPos(HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowPos(m_hWnd, hWndInsertAfter, x, y, cx, cy, nFlags);
        }

        BOOL SetWindowPos(HWND hWndInsertAfter, LPCRECT lpRect, UINT nFlags)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowPos(m_hWnd, hWndInsertAfter, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, nFlags);
        }

        UINT ArrangeIconicWindows()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ArrangeIconicWindows(m_hWnd);
        }

        BOOL BringWindowToTop()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::BringWindowToTop(m_hWnd);
        }

        BOOL GetWindowRect(LPRECT lpRect) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowRect(m_hWnd, lpRect);
        }

        BOOL GetClientRect(LPRECT lpRect) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetClientRect(m_hWnd, lpRect);
        }

        BOOL GetWindowPlacement(WINDOWPLACEMENT FAR* lpwndpl) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowPlacement(m_hWnd, lpwndpl);
        }

        BOOL SetWindowPlacement(const WINDOWPLACEMENT FAR* lpwndpl)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowPlacement(m_hWnd, lpwndpl);
        }

// Coordinate Mapping Functions

        BOOL ClientToScreen(LPPOINT lpPoint) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ClientToScreen(m_hWnd, lpPoint);
        }

        BOOL ClientToScreen(LPRECT lpRect) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                if(!::ClientToScreen(m_hWnd, (LPPOINT)lpRect))
                        return FALSE;
                return ::ClientToScreen(m_hWnd, ((LPPOINT)lpRect)+1);
        }

        BOOL ScreenToClient(LPPOINT lpPoint) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ScreenToClient(m_hWnd, lpPoint);
        }

        BOOL ScreenToClient(LPRECT lpRect) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                if(!::ScreenToClient(m_hWnd, (LPPOINT)lpRect))
                        return FALSE;
                return ::ScreenToClient(m_hWnd, ((LPPOINT)lpRect)+1);
        }

        int MapWindowPoints(HWND hWndTo, LPPOINT lpPoint, UINT nCount) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::MapWindowPoints(m_hWnd, hWndTo, lpPoint, nCount);
        }

        int MapWindowPoints(HWND hWndTo, LPRECT lpRect) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::MapWindowPoints(m_hWnd, hWndTo, (LPPOINT)lpRect, 2);
        }

// Update and Painting Functions

        HDC BeginPaint(LPPAINTSTRUCT lpPaint)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::BeginPaint(m_hWnd, lpPaint);
        }

        void EndPaint(LPPAINTSTRUCT lpPaint)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::EndPaint(m_hWnd, lpPaint);
        }

        HDC GetDC()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDC(m_hWnd);
        }

        HDC GetWindowDC()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowDC(m_hWnd);
        }

        int ReleaseDC(HDC hDC)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ReleaseDC(m_hWnd, hDC);
        }

        void Print(HDC hDC, DWORD dwFlags) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_PRINT, (WPARAM)hDC, dwFlags);
        }

        void PrintClient(HDC hDC, DWORD dwFlags) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_PRINTCLIENT, (WPARAM)hDC, dwFlags);
        }

        BOOL UpdateWindow()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::UpdateWindow(m_hWnd);
        }

        void SetRedraw(BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_SETREDRAW, (WPARAM)bRedraw, 0);
        }

        BOOL GetUpdateRect(LPRECT lpRect, BOOL bErase = FALSE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetUpdateRect(m_hWnd, lpRect, bErase);
        }

        int GetUpdateRgn(HRGN hRgn, BOOL bErase = FALSE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetUpdateRgn(m_hWnd, hRgn, bErase);
        }

        BOOL Invalidate(BOOL bErase = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::InvalidateRect(m_hWnd, NULL, bErase);
        }

        BOOL InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::InvalidateRect(m_hWnd, lpRect, bErase);
        }

        BOOL ValidateRect(LPCRECT lpRect)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ValidateRect(m_hWnd, lpRect);
        }

        void InvalidateRgn(HRGN hRgn, BOOL bErase = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::InvalidateRgn(m_hWnd, hRgn, bErase);
        }

        BOOL ValidateRgn(HRGN hRgn)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ValidateRgn(m_hWnd, hRgn);
        }

        BOOL ShowWindow(int nCmdShow)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ShowWindow(m_hWnd, nCmdShow);
        }

        BOOL IsWindowVisible() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsWindowVisible(m_hWnd);
        }

        BOOL ShowOwnedPopups(BOOL bShow = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ShowOwnedPopups(m_hWnd, bShow);
        }

        HDC GetDCEx(HRGN hRgnClip, DWORD flags)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDCEx(m_hWnd, hRgnClip, flags);
        }

        BOOL LockWindowUpdate(BOOL bLock = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::LockWindowUpdate(bLock ? m_hWnd : NULL);
        }

        BOOL RedrawWindow(LPCRECT lpRectUpdate = NULL, HRGN hRgnUpdate = NULL, UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::RedrawWindow(m_hWnd, lpRectUpdate, hRgnUpdate, flags);
        }

// Timer Functions

        UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetTimer(m_hWnd, nIDEvent, nElapse, NULL);
        }

        BOOL KillTimer(UINT_PTR nIDEvent)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::KillTimer(m_hWnd, nIDEvent);
        }

// Window State Functions

        BOOL IsWindowEnabled() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsWindowEnabled(m_hWnd);
        }

        BOOL EnableWindow(BOOL bEnable = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::EnableWindow(m_hWnd, bEnable);
        }

        HWND SetActiveWindow()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetActiveWindow(m_hWnd);
        }

        HWND SetCapture()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetCapture(m_hWnd);
        }

        HWND SetFocus()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetFocus(m_hWnd);
        }

// Dialog-Box Item Functions

        BOOL CheckDlgButton(int nIDButton, UINT nCheck)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::CheckDlgButton(m_hWnd, nIDButton, nCheck);
        }

        BOOL CheckRadioButton(int nIDFirstButton, int nIDLastButton, int nIDCheckButton)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::CheckRadioButton(m_hWnd, nIDFirstButton, nIDLastButton, nIDCheckButton);
        }

        int DlgDirList(LPTSTR lpPathSpec, int nIDListBox, int nIDStaticPath, UINT nFileType)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DlgDirList(m_hWnd, lpPathSpec, nIDListBox, nIDStaticPath, nFileType);
        }

        int DlgDirListComboBox(LPTSTR lpPathSpec, int nIDComboBox, int nIDStaticPath, UINT nFileType)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DlgDirListComboBox(m_hWnd, lpPathSpec, nIDComboBox, nIDStaticPath, nFileType);
        }

        BOOL DlgDirSelect(LPTSTR lpString, int nCount, int nIDListBox)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DlgDirSelectEx(m_hWnd, lpString, nCount, nIDListBox);
        }

        BOOL DlgDirSelectComboBox(LPTSTR lpString, int nCount, int nIDComboBox)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DlgDirSelectComboBoxEx(m_hWnd, lpString, nCount, nIDComboBox);
        }

        UINT GetDlgItemInt(int nID, BOOL* lpTrans = NULL, BOOL bSigned = TRUE) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDlgItemInt(m_hWnd, nID, lpTrans, bSigned);
        }

        UINT GetDlgItemText(int nID, LPTSTR lpStr, int nMaxCount) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDlgItemText(m_hWnd, nID, lpStr, nMaxCount);
        }
        BOOL GetDlgItemText(int nID, BSTR& bstrText) const
        {
                ATLASSERT(::IsWindow(m_hWnd));

                HWND hWndCtl = GetDlgItem(nID);
                if(hWndCtl == NULL)
                        return FALSE;

                return CWindow(hWndCtl).GetWindowText(bstrText);
        }
        HWND GetNextDlgGroupItem(HWND hWndCtl, BOOL bPrevious = FALSE) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetNextDlgGroupItem(m_hWnd, hWndCtl, bPrevious);
        }

        HWND GetNextDlgTabItem(HWND hWndCtl, BOOL bPrevious = FALSE) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetNextDlgTabItem(m_hWnd, hWndCtl, bPrevious);
        }

        UINT IsDlgButtonChecked(int nIDButton) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsDlgButtonChecked(m_hWnd, nIDButton);
        }

        LRESULT SendDlgItemMessage(int nID, UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SendDlgItemMessage(m_hWnd, nID, message, wParam, lParam);
        }

        BOOL SetDlgItemInt(int nID, UINT nValue, BOOL bSigned = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetDlgItemInt(m_hWnd, nID, nValue, bSigned);
        }

        BOOL SetDlgItemText(int nID, LPCTSTR lpszString)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetDlgItemText(m_hWnd, nID, lpszString);
        }

#ifndef _ATL_NO_HOSTING
        HRESULT GetDlgControl(int nID, REFIID iid, void** ppUnk)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ATLASSERT(ppUnk != NULL);
                HRESULT hr = E_FAIL;
                HWND hWndCtrl = GetDlgItem(nID);
                if (hWndCtrl != NULL)
                {
                        if (ppUnk == NULL)
                        {
                                return E_POINTER;
                        }
                        *ppUnk = NULL;
                        CComPtr<IUnknown> spUnk;
                        hr = AtlAxGetControl(hWndCtrl, &spUnk);
                        if (SUCCEEDED(hr))
                                hr = spUnk->QueryInterface(iid, ppUnk);
                }
                return hr;
        }
#endif //!_ATL_NO_HOSTING

// Scrolling Functions

        int GetScrollPos(int nBar) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetScrollPos(m_hWnd, nBar);
        }

        BOOL GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetScrollRange(m_hWnd, nBar, lpMinPos, lpMaxPos);
        }

        BOOL ScrollWindow(int xAmount, int yAmount, LPCRECT lpRect = NULL, LPCRECT lpClipRect = NULL)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ScrollWindow(m_hWnd, xAmount, yAmount, lpRect, lpClipRect);
        }

        int ScrollWindowEx(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate, UINT uFlags)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ScrollWindowEx(m_hWnd, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate, uFlags);
        }

        int ScrollWindowEx(int dx, int dy, UINT uFlags, LPCRECT lpRectScroll = NULL, LPCRECT lpRectClip = NULL, HRGN hRgnUpdate = NULL, LPRECT lpRectUpdate = NULL)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ScrollWindowEx(m_hWnd, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate, uFlags);
        }

        int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetScrollPos(m_hWnd, nBar, nPos, bRedraw);
        }

        BOOL SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetScrollRange(m_hWnd, nBar, nMinPos, nMaxPos, bRedraw);
        }

        BOOL ShowScrollBar(UINT nBar, BOOL bShow = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ShowScrollBar(m_hWnd, nBar, bShow);
        }

        BOOL EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::EnableScrollBar(m_hWnd, uSBFlags, uArrowFlags);
        }

// Window Access Functions

        HWND ChildWindowFromPoint(POINT point) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ChildWindowFromPoint(m_hWnd, point);
        }

        HWND ChildWindowFromPointEx(POINT point, UINT uFlags) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ChildWindowFromPointEx(m_hWnd, point, uFlags);
        }

        HWND GetTopWindow() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetTopWindow(m_hWnd);
        }

        HWND GetWindow(UINT nCmd) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindow(m_hWnd, nCmd);
        }

        HWND GetLastActivePopup() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetLastActivePopup(m_hWnd);
        }

        BOOL IsChild(HWND hWnd) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsChild(m_hWnd, hWnd);
        }

        HWND GetParent() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetParent(m_hWnd);
        }

        HWND SetParent(HWND hWndNewParent)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetParent(m_hWnd, hWndNewParent);
        }

// Window Tree Access

        int GetDlgCtrlID() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDlgCtrlID(m_hWnd);
        }

        int SetDlgCtrlID(int nID)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (int)::SetWindowLong(m_hWnd, GWL_ID, nID);
        }

        HWND GetDlgItem(int nID) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetDlgItem(m_hWnd, nID);
        }

// Alert Functions

        BOOL FlashWindow(BOOL bInvert)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::FlashWindow(m_hWnd, bInvert);
        }

        int MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption = _T(""), UINT nType = MB_OK)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::MessageBox(m_hWnd, lpszText, lpszCaption, nType);
        }

// Clipboard Functions

        BOOL ChangeClipboardChain(HWND hWndNewNext)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ChangeClipboardChain(m_hWnd, hWndNewNext);
        }

        HWND SetClipboardViewer()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetClipboardViewer(m_hWnd);
        }

        BOOL OpenClipboard()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::OpenClipboard(m_hWnd);
        }

// Caret Functions

        BOOL CreateCaret(HBITMAP hBitmap)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::CreateCaret(m_hWnd, hBitmap, 0, 0);
        }

        BOOL CreateSolidCaret(int nWidth, int nHeight)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::CreateCaret(m_hWnd, (HBITMAP)0, nWidth, nHeight);
        }

        BOOL CreateGrayCaret(int nWidth, int nHeight)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::CreateCaret(m_hWnd, (HBITMAP)1, nWidth, nHeight);
        }

        BOOL HideCaret()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::HideCaret(m_hWnd);
        }

        BOOL ShowCaret()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ShowCaret(m_hWnd);
        }

#ifdef _INC_SHELLAPI
// Drag-Drop Functions
        void DragAcceptFiles(BOOL bAccept = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd)); ::DragAcceptFiles(m_hWnd, bAccept);
        }
#endif

// Icon Functions

        HICON SetIcon(HICON hIcon, BOOL bBigIcon = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (HICON)::SendMessage(m_hWnd, WM_SETICON, bBigIcon, (LPARAM)hIcon);
        }

        HICON GetIcon(BOOL bBigIcon = TRUE) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (HICON)::SendMessage(m_hWnd, WM_GETICON, bBigIcon, 0);
        }

// Help Functions

        BOOL WinHelp(LPCTSTR lpszHelp, UINT nCmd = HELP_CONTEXT, DWORD dwData = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::WinHelp(m_hWnd, lpszHelp, nCmd, dwData);
        }

        BOOL SetWindowContextHelpId(DWORD dwContextHelpId)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowContextHelpId(m_hWnd, dwContextHelpId);
        }

        DWORD GetWindowContextHelpId() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowContextHelpId(m_hWnd);
        }

// Hot Key Functions

        int SetHotKey(WORD wVirtualKeyCode, WORD wModifiers)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (int)::SendMessage(m_hWnd, WM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0);
        }

        DWORD GetHotKey() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return (DWORD)::SendMessage(m_hWnd, WM_GETHOTKEY, 0, 0);
        }

// Misc. Operations

//N new
        BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetScrollInfo(m_hWnd, nBar, lpScrollInfo);
        }
        BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetScrollInfo(m_hWnd, nBar, lpScrollInfo, bRedraw);
        }
        BOOL IsDialogMessage(LPMSG lpMsg)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsDialogMessage(m_hWnd, lpMsg);
        }

        void NextDlgCtrl() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_NEXTDLGCTL, 0, 0L);
        }
        void PrevDlgCtrl() const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_NEXTDLGCTL, 1, 0L);
        }
        void GotoDlgCtrl(HWND hWndCtrl) const
        {
                ATLASSERT(::IsWindow(m_hWnd));
                ::SendMessage(m_hWnd, WM_NEXTDLGCTL, (WPARAM)hWndCtrl, 1L);
        }

        BOOL ResizeClient(int nWidth, int nHeight, BOOL bRedraw = TRUE)
        {
                ATLASSERT(::IsWindow(m_hWnd));

                RECT rcWnd;
                if(!GetClientRect(&rcWnd))
                        return FALSE;

                if(nWidth != -1)
                        rcWnd.right = nWidth;
                if(nHeight != -1)
                        rcWnd.bottom = nHeight;

                if(!::AdjustWindowRectEx(&rcWnd, GetStyle(), (!(GetStyle() & WS_CHILD) && (GetMenu() != NULL)), GetExStyle()))
                        return FALSE;

                UINT uFlags = SWP_NOZORDER | SWP_NOMOVE;
                if(!bRedraw)
                        uFlags |= SWP_NOREDRAW;

                return SetWindowPos(NULL, 0, 0, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, uFlags);
        }

        int GetWindowRgn(HRGN hRgn)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowRgn(m_hWnd, hRgn);
        }
        int SetWindowRgn(HRGN hRgn, BOOL bRedraw = FALSE)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::SetWindowRgn(m_hWnd, hRgn, bRedraw);
        }
        HDWP DeferWindowPos(HDWP hWinPosInfo, HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DeferWindowPos(hWinPosInfo, m_hWnd, hWndInsertAfter, x, y, cx, cy, uFlags);
        }
        DWORD GetWindowThreadID()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::GetWindowThreadProcessId(m_hWnd, NULL);
        }
        DWORD GetWindowProcessID()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                DWORD dwProcessID;
                ::GetWindowThreadProcessId(m_hWnd, &dwProcessID);
                return dwProcessID;
        }
        BOOL IsWindow()
        {
                return ::IsWindow(m_hWnd);
        }
        BOOL IsWindowUnicode()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::IsWindowUnicode(m_hWnd);
        }
        BOOL IsParentDialog()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                TCHAR szBuf[8]; // "#32770" + NUL character
                GetClassName(GetParent(), szBuf, sizeof(szBuf)/sizeof(TCHAR));
                return lstrcmp(szBuf, _T("#32770")) == 0;
        }
        BOOL ShowWindowAsync(int nCmdShow)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::ShowWindowAsync(m_hWnd, nCmdShow);
        }

        HWND GetDescendantWindow(int nID) const
        {
                ATLASSERT(::IsWindow(m_hWnd));

                // 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, hWndTmp;
                CWindow wnd;
                if((hWndChild = ::GetDlgItem(m_hWnd, nID)) != NULL)
                {
                        if(::GetTopWindow(hWndChild) != NULL)
                        {
                                // children with the same ID as their parent have priority
                                wnd.Attach(hWndChild);
                                hWndTmp = wnd.GetDescendantWindow(nID);
                                if(hWndTmp != NULL)
                                        return hWndTmp;
                        }
                        return hWndChild;
                }

                // walk each child
                for(hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
                        hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
                {
                        wnd.Attach(hWndChild);
                        hWndTmp = wnd.GetDescendantWindow(nID);
                        if(hWndTmp != NULL)
                                return hWndTmp;
                }

                return NULL;    // not found
        }

        void SendMessageToDescendants(UINT message, WPARAM wParam = 0, LPARAM lParam = 0, BOOL bDeep = TRUE)
        {
                CWindow wnd;
                for(HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
                        hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
                {
                        ::SendMessage(hWndChild, message, wParam, lParam);

                        if(bDeep && ::GetTopWindow(hWndChild) != NULL)
                        {
                                // send to child windows after parent
                                wnd.Attach(hWndChild);
                                wnd.SendMessageToDescendants(message, wParam, lParam, bDeep);
                        }
                }
        }

        BOOL CenterWindow(HWND hWndCenter = NULL)
        {
                ATLASSERT(::IsWindow(m_hWnd));

                // determine owner window to center against
                DWORD dwStyle = GetStyle();
                if(hWndCenter == NULL)
                {
                        if(dwStyle & WS_CHILD)
                                hWndCenter = ::GetParent(m_hWnd);
                        else
                                hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
                }

                // get coordinates of the window relative to its parent
                RECT rcDlg;
                ::GetWindowRect(m_hWnd, &rcDlg);
                RECT rcArea;
                RECT rcCenter;
                HWND hWndParent;
                if(!(dwStyle & WS_CHILD))
                {
                        // don't center against invisible or minimized windows
                        if(hWndCenter != NULL)
                        {
                                DWORD L_dwStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
                                if(!(L_dwStyle & WS_VISIBLE) || (L_dwStyle & WS_MINIMIZE))
                                        hWndCenter = NULL;
                        }

                        // center within screen coordinates
                        ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);
                        if(hWndCenter == NULL)
                                rcCenter = rcArea;
                        else
                                ::GetWindowRect(hWndCenter, &rcCenter);
                }
                else
                {
                        // center within parent client coordinates
                        hWndParent = ::GetParent(m_hWnd);
                        ATLASSERT(::IsWindow(hWndParent));

                        ::GetClientRect(hWndParent, &rcArea);
                        ATLASSERT(::IsWindow(hWndCenter));
                        ::GetClientRect(hWndCenter, &rcCenter);
                        ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
                }

                int DlgWidth = rcDlg.right - rcDlg.left;
                int DlgHeight = rcDlg.bottom - rcDlg.top;

                // find dialog's upper left based on rcCenter
                int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
                int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;

                // if the dialog is outside the screen, move it inside
                if(xLeft < rcArea.left)
                        xLeft = rcArea.left;
                else if(xLeft + DlgWidth > rcArea.right)
                        xLeft = rcArea.right - DlgWidth;

                if(yTop < rcArea.top)
                        yTop = rcArea.top;
                else if(yTop + DlgHeight > rcArea.bottom)
                        yTop = rcArea.bottom - DlgHeight;

                // map screen coordinates to child coordinates
                return ::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1,
                        SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
        }

        BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));

                DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
                DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
                if(dwStyle == dwNewStyle)
                        return FALSE;

                ::SetWindowLong(m_hWnd, GWL_STYLE, dwNewStyle);
                if(nFlags != 0)
                {
                        ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,
                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
                }

                return TRUE;
        }

        BOOL ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
        {
                ATLASSERT(::IsWindow(m_hWnd));

                DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
                DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
                if(dwStyle == dwNewStyle)
                        return FALSE;

                ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwNewStyle);
                if(nFlags != 0)
                {
                        ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,
                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
                }

                return TRUE;
        }

        BOOL GetWindowText(BSTR* pbstrText)
        {
                return GetWindowText(*pbstrText);
        }
        BOOL GetWindowText(BSTR& bstrText)
        {
                USES_CONVERSION;
                ATLASSERT(::IsWindow(m_hWnd));
                if (bstrText != NULL)
                {
                        SysFreeString(bstrText);
                        bstrText = NULL;
                }

                int nLen = ::GetWindowTextLength(m_hWnd);
                if(nLen == 0)
                {
                        bstrText = ::SysAllocString(OLESTR(""));
                        return (bstrText != NULL) ? TRUE : FALSE;
                }

                LPTSTR lpszText = (LPTSTR)_alloca((nLen+1)*sizeof(TCHAR));

                if(!::GetWindowText(m_hWnd, lpszText, nLen+1))
                        return FALSE;
                
                bstrText = ::SysAllocString(T2OLE(lpszText));
                return (bstrText != NULL) ? TRUE : FALSE;
        }
        HWND GetTopLevelParent() const
        {
                ATLASSERT(::IsWindow(m_hWnd));

                HWND hWndParent = m_hWnd;
                HWND hWndTmp;
                while((hWndTmp = ::GetParent(hWndParent)) != NULL)
                        hWndParent = hWndTmp;

                return hWndParent;
        }

        HWND GetTopLevelWindow() const
        {
                ATLASSERT(::IsWindow(m_hWnd));

                HWND hWndParent;
                HWND hWndTmp = m_hWnd;

                do
                {
                        hWndParent = hWndTmp;
                        hWndTmp = (::GetWindowLong(hWndParent, GWL_STYLE) & WS_CHILD) ? ::GetParent(hWndParent) : ::GetWindow(hWndParent, GW_OWNER);
                }
                while(hWndTmp != NULL);

                return hWndParent;
        }
};

_declspec(selectany) RECT CWindow::rcDefault = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 };

/////////////////////////////////////////////////////////////////////////////
// CAxWindow - client side for an ActiveX host window

#ifndef _ATL_NO_HOSTING

template <class TBase /* = CWindow */>
class CAxWindowT : public TBase
{
public:
// Constructors
        CAxWindowT(HWND hWnd = NULL) : TBase(hWnd)
        { }

        CAxWindowT< TBase >& operator=(HWND hWnd)
        {
                m_hWnd = hWnd;
                return *this;
        }

// Attributes
        static LPCTSTR GetWndClassName()
        {
                return _T("AtlAxWin");
        }

// Operations
        HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
                        DWORD dwStyle = 0, DWORD dwExStyle = 0,
                        UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                return CWindow::Create(GetWndClassName(), hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
        }
        HWND Create(HWND hWndParent, LPRECT lpRect = NULL, LPCTSTR szWindowName = NULL,
                        DWORD dwStyle = 0, DWORD dwExStyle = 0,
                        HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
        {
                return CWindow::Create(GetWndClassName(), hWndParent, lpRect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
        }

        HRESULT CreateControl(LPCOLESTR lpszName, IStream* pStream = NULL, IUnknown** ppUnkContainer = NULL)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return AtlAxCreateControl(lpszName, m_hWnd, pStream, ppUnkContainer);
        }

        HRESULT CreateControl(DWORD dwResID, IStream* pStream = NULL, IUnknown** ppUnkContainer = NULL)
        {
                TCHAR szModule[_MAX_PATH];
                DWORD len = GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH);

                if (0 == len || (sizeof szModule / sizeof szModule[0]) == len) 
                {        // GetModuleFileName failed
                        return HRESULT_FROM_WIN32(::GetLastError());        
                }

                CComBSTR bstrURL(OLESTR("res://"));
                bstrURL.Append(szModule);
                bstrURL.Append(OLESTR("/"));
                TCHAR szResID[11];
                wsprintf(szResID, _T("%0d"), dwResID);
                bstrURL.Append(szResID);

                ATLASSERT(::IsWindow(m_hWnd));
                return AtlAxCreateControl(bstrURL, m_hWnd, pStream, ppUnkContainer);
        }

        HRESULT CreateControlEx(LPCOLESTR lpszName, IStream* pStream = NULL,
                        IUnknown** ppUnkContainer = NULL, IUnknown** ppUnkControl = NULL,
                        REFIID iidSink = IID_NULL, IUnknown* punkSink = NULL)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return AtlAxCreateControlEx(lpszName, m_hWnd, pStream, ppUnkContainer, ppUnkControl, iidSink, punkSink);
        }

        HRESULT CreateControlEx(DWORD dwResID,  IStream* pStream = NULL,
                        IUnknown** ppUnkContainer = NULL, IUnknown** ppUnkControl = NULL,
                        REFIID iidSink = IID_NULL, IUnknown* punkSink = NULL)
        {
                TCHAR szModule[_MAX_PATH];
                DWORD len = GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH);

                if (0 == len || (sizeof szModule / sizeof szModule[0]) == len) 
                {        // GetModuleFileName failed
                        return HRESULT_FROM_WIN32(::GetLastError());        
                }

                CComBSTR bstrURL(OLESTR("res://"));
                bstrURL.Append(szModule);
                bstrURL.Append(OLESTR("/"));
                TCHAR szResID[11];
                wsprintf(szResID, _T("%0d"), dwResID);
                bstrURL.Append(szResID);

                ATLASSERT(::IsWindow(m_hWnd));
                return AtlAxCreateControlEx(bstrURL, m_hWnd, pStream, ppUnkContainer, ppUnkControl, iidSink, punkSink);
        }

        HRESULT AttachControl(IUnknown* pControl, IUnknown** ppUnkContainer)
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return AtlAxAttachControl(pControl, m_hWnd, ppUnkContainer);
        }
        HRESULT QueryHost(REFIID iid, void** ppUnk)
        {
                ATLASSERT(ppUnk != NULL);
                HRESULT hr;

                if (NULL == ppUnk)
                {
                        return E_POINTER;
                }
                *ppUnk = NULL;                                                
                CComPtr<IUnknown> spUnk;
                hr = AtlAxGetHost(m_hWnd, &spUnk);
                if (SUCCEEDED(hr))
                        hr = spUnk->QueryInterface(iid, ppUnk);
                return hr;
        }
        template <class Q>
        HRESULT QueryHost(Q** ppUnk)
        {
                return QueryHost(__uuidof(Q), (void**)ppUnk);
        }
        HRESULT QueryControl(REFIID iid, void** ppUnk)
        {
                ATLASSERT(ppUnk != NULL);
                HRESULT hr;
                if (NULL == ppUnk)
                {
                        return E_POINTER;
                }
                *ppUnk = NULL;                                        
                CComPtr<IUnknown> spUnk;
                hr = AtlAxGetControl(m_hWnd, &spUnk);
                if (SUCCEEDED(hr))
                        hr = spUnk->QueryInterface(iid, ppUnk);
                return hr;
        }
        template <class Q>
        HRESULT QueryControl(Q** ppUnk)
        {
                return QueryControl(__uuidof(Q), (void**)ppUnk);
        }
        HRESULT SetExternalDispatch(IDispatch* pDisp)
        {
                HRESULT hr;
                CComPtr<IAxWinHostWindow> spHost;
                hr = QueryHost(IID_IAxWinHostWindow, (void**)&spHost);
                if (SUCCEEDED(hr))
                        hr = spHost->SetExternalDispatch(pDisp);
                return hr;
        }
        HRESULT SetExternalUIHandler(IDocHostUIHandlerDispatch* pUIHandler)
        {
                HRESULT hr;
                CComPtr<IAxWinHostWindow> spHost;
                hr = QueryHost(IID_IAxWinHostWindow, (void**)&spHost);
                if (SUCCEEDED(hr))
                        hr = spHost->SetExternalUIHandler(pUIHandler);
                return hr;
        }
};

typedef CAxWindowT<CWindow> CAxWindow;

#endif //_ATL_NO_HOSTING

/////////////////////////////////////////////////////////////////////////////
// WindowProc thunks

class CWndProcThunk
{
public:
	_AtlCreateWndData cd;
        CStdCallThunk thunk;

        void Init(WNDPROC proc, void* pThis)
        {
		thunk.Init((DWORD_PTR)proc, pThis);
        }
};

/////////////////////////////////////////////////////////////////////////////
// CMessageMap - abstract class that provides an interface for message maps

class ATL_NO_VTABLE CMessageMap
{
public:
        virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                LRESULT& lResult, DWORD dwMsgMapID) = 0;
};

/////////////////////////////////////////////////////////////////////////////
// Message map

#define BEGIN_MSG_MAP(theClass) \
public: \
        BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
        { \
                BOOL bHandled = TRUE; \
                hWnd; \
                uMsg; \
                wParam; \
                lParam; \
                lResult; \
                bHandled; \
                switch(dwMsgMapID) \
                { \
                case 0:

#define ALT_MSG_MAP(msgMapID) \
                break; \
                case msgMapID:

#define MESSAGE_HANDLER(msg, func) \
        if(uMsg == msg) \
        { \
                bHandled = TRUE; \
                lResult = func(uMsg, wParam, lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define MESSAGE_RANGE_HANDLER(msgFirst, msgLast, func) \
        if(uMsg >= msgFirst && uMsg <= msgLast) \
        { \
                bHandled = TRUE; \
                lResult = func(uMsg, wParam, lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define COMMAND_HANDLER(id, code, func) \
        if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \
        { \
                bHandled = TRUE; \
                lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define COMMAND_ID_HANDLER(id, func) \
        if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
        { \
                bHandled = TRUE; \
                lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define COMMAND_CODE_HANDLER(code, func) \
        if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \
        { \
                bHandled = TRUE; \
                lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define COMMAND_RANGE_HANDLER(idFirst, idLast, func) \
        if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) \
        { \
                bHandled = TRUE; \
                lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define NOTIFY_HANDLER(id, cd, func) \
        if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \
        { \
                bHandled = TRUE; \
                lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define NOTIFY_ID_HANDLER(id, func) \
        if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
        { \
                bHandled = TRUE; \
                lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define NOTIFY_CODE_HANDLER(cd, func) \
        if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
        { \
                bHandled = TRUE; \
                lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \
        if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
        { \
                bHandled = TRUE; \
                lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define CHAIN_MSG_MAP(theChainClass) \
        { \
                if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
                        return TRUE; \
        }

#define CHAIN_MSG_MAP_MEMBER(theChainMember) \
        { \
                if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
                        return TRUE; \
        }

#define CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) \
        { \
                if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
                        return TRUE; \
        }

#define CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) \
        { \
                if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
                        return TRUE; \
        }

#define CHAIN_MSG_MAP_DYNAMIC(dynaChainID) \
        { \
                if(CDynamicChain::CallChain(dynaChainID, hWnd, uMsg, wParam, lParam, lResult)) \
                        return TRUE; \
        }

#define END_MSG_MAP() \
                        break; \
                default: \
                        ATLTRACE2(atlTraceWindowing, 0, _T("Invalid message map ID (%i)\n"), dwMsgMapID); \
                        ATLASSERT(FALSE); \
                        break; \
                } \
                return FALSE; \
        }


// Handler prototypes:
//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);


// Empty message map macro

#define DECLARE_EMPTY_MSG_MAP() \
public: \
        BOOL ProcessWindowMessage(HWND, UINT, WPARAM, LPARAM, LRESULT&, DWORD) \
        { \
                return FALSE; \
        }

// Message reflection macros

#define REFLECT_NOTIFICATIONS() \
        { \
                bHandled = TRUE; \
                lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
                if(bHandled) \
                        return TRUE; \
        }

#define DEFAULT_REFLECTION_HANDLER() \
        if(DefaultReflectionHandler(hWnd, uMsg, wParam, lParam, lResult)) \
                return TRUE;

/////////////////////////////////////////////////////////////////////////////
// CDynamicChain - provides support for dynamic chaining

class CDynamicChain
{
public:
        struct ATL_CHAIN_ENTRY
        {
                DWORD m_dwChainID;
                CMessageMap* m_pObject;
                DWORD m_dwMsgMapID;
        };

        CSimpleArray<ATL_CHAIN_ENTRY*> m_aChainEntry;

        CDynamicChain()
        { }

        ~CDynamicChain()
        {
                for(int i = 0; i < m_aChainEntry.GetSize(); i++)
                {
                        if(m_aChainEntry[i] != NULL)
                                delete m_aChainEntry[i];
                }
        }

        BOOL SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID = 0)
        {
        // first search for an existing entry

                for(int i = 0; i < m_aChainEntry.GetSize(); i++)
                {
                        if(m_aChainEntry[i] != NULL && m_aChainEntry[i]->m_dwChainID == dwChainID)
                        {
                                m_aChainEntry[i]->m_pObject = pObject;
                                m_aChainEntry[i]->m_dwMsgMapID = dwMsgMapID;
                                return TRUE;
                        }
                }

        // create a new one

                ATL_CHAIN_ENTRY* pEntry = NULL;
                ATLTRY(pEntry = new ATL_CHAIN_ENTRY);

                if(pEntry == NULL)
                        return FALSE;

                pEntry->m_dwChainID = dwChainID;
                pEntry->m_pObject = pObject;
                pEntry->m_dwMsgMapID = dwMsgMapID;

        // search for an empty one

                for(i = 0; i < m_aChainEntry.GetSize(); i++)
                {
                        if(m_aChainEntry[i] == NULL)
                        {
                                m_aChainEntry[i] = pEntry;
                                return TRUE;
                        }
                }

        // add a new one

                BOOL bRet = m_aChainEntry.Add(pEntry);

                if(!bRet)
                {
                        delete pEntry;
                        return FALSE;
                }

                return TRUE;
        }

        BOOL RemoveChainEntry(DWORD dwChainID)
        {
                for(int i = 0; i < m_aChainEntry.GetSize(); i++)
                {
                        if(m_aChainEntry[i] != NULL && m_aChainEntry[i]->m_dwChainID == dwChainID)
                        {
                                delete m_aChainEntry[i];
                                m_aChainEntry[i] = NULL;
                                return TRUE;
                        }
                }

                return FALSE;
        }

        BOOL CallChain(DWORD dwChainID, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult)
        {
                for(int i = 0; i < m_aChainEntry.GetSize(); i++)
                {
                        if(m_aChainEntry[i] != NULL && m_aChainEntry[i]->m_dwChainID == dwChainID)
                                return (m_aChainEntry[i]->m_pObject)->ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, m_aChainEntry[i]->m_dwMsgMapID);
                }

                return FALSE;
        }
};

/////////////////////////////////////////////////////////////////////////////
// CWndClassInfo - Manages Windows class information

#define DECLARE_WND_CLASS(WndClassName) \
static CWndClassInfo& GetWndClassInfo() \
{ \
        static CWndClassInfo wc = \
        { \
                { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, \
                  0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
                NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
        }; \
        return wc; \
}

#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \
static CWndClassInfo& GetWndClassInfo() \
{ \
        static CWndClassInfo wc = \
        { \
                { sizeof(WNDCLASSEX), style, StartWindowProc, \
                  0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
                NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
        }; \
        return wc; \
}

#define DECLARE_WND_SUPERCLASS(WndClassName, OrigWndClassName) \
static CWndClassInfo& GetWndClassInfo() \
{ \
        static CWndClassInfo wc = \
        { \
                { sizeof(WNDCLASSEX), 0, StartWindowProc, \
                  0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
                OrigWndClassName, NULL, NULL, TRUE, 0, _T("") \
        }; \
        return wc; \
}

/////////////////////////////////////////////////////////////////////////////
// CWinTraits - Defines various default values for a window

template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
class CWinTraits
{
public:
        static DWORD GetWndStyle(DWORD dwStyle)
        {
                return dwStyle == 0 ? t_dwStyle : dwStyle;
        }
        static DWORD GetWndExStyle(DWORD dwExStyle)
        {
                return dwExStyle == 0 ? t_dwExStyle : dwExStyle;
        }
};

typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0>                                        CControlWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE>                CFrameWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD>        CMDIChildWinTraits;

typedef CWinTraits<0, 0> CNullTraits;

template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0, class TWinTraits = CControlWinTraits>
class CWinTraitsOR
{
public:
        static DWORD GetWndStyle(DWORD dwStyle)
        {
                return dwStyle | t_dwStyle | TWinTraits::GetWndStyle(dwStyle);
        }
        static DWORD GetWndExStyle(DWORD dwExStyle)
        {
                return dwExStyle | t_dwExStyle | TWinTraits::GetWndExStyle(dwExStyle);
        }
};

/////////////////////////////////////////////////////////////////////////////
// CWindowImpl - Implements a window

template <class TBase = CWindow>
class ATL_NO_VTABLE CWindowImplRoot : public TBase, public CMessageMap
{
public:
        CWndProcThunk m_thunk;
        const MSG* m_pCurrentMsg;

// Constructor/destructor
        CWindowImplRoot() : m_pCurrentMsg(NULL)
        { }

        ~CWindowImplRoot()
        {
#ifdef _DEBUG
                if(m_hWnd != NULL)        // should be cleared in WindowProc
                {
                        ATLTRACE2(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed\n"));
                        ATLASSERT(FALSE);
                }
#endif //_DEBUG
        }

// Current message
        const MSG* GetCurrentMessage() const
        {
                return m_pCurrentMsg;
        }

// Message reflection support
        LRESULT ReflectNotifications(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
        static BOOL DefaultReflectionHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult);
};

template <class TBase>
LRESULT CWindowImplRoot< TBase >::ReflectNotifications(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
        HWND hWndChild = NULL;

        switch(uMsg)
        {
        case WM_COMMAND:
                if(lParam != NULL)        // not from a menu
                        hWndChild = (HWND)lParam;
                break;
        case WM_NOTIFY:
                hWndChild = ((LPNMHDR)lParam)->hwndFrom;
                break;
        case WM_PARENTNOTIFY:
                switch(LOWORD(wParam))
                {
                case WM_CREATE:
                case WM_DESTROY:
                        hWndChild = (HWND)lParam;
                        break;
                default:
                        hWndChild = GetDlgItem(HIWORD(wParam));
                        break;
                }
                break;
        case WM_DRAWITEM:
                if(wParam)        // not from a menu
                        hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem;
                break;
        case WM_MEASUREITEM:
                if(wParam)        // not from a menu
                        hWndChild = GetDlgItem(((LPMEASUREITEMSTRUCT)lParam)->CtlID);
                break;
        case WM_COMPAREITEM:
                if(wParam)        // not from a menu
                        hWndChild = GetDlgItem(((LPCOMPAREITEMSTRUCT)lParam)->CtlID);
                break;
        case WM_DELETEITEM:
                if(wParam)        // not from a menu
                        hWndChild = GetDlgItem(((LPDELETEITEMSTRUCT)lParam)->CtlID);
                break;
        case WM_VKEYTOITEM:
        case WM_CHARTOITEM:
        case WM_HSCROLL:
        case WM_VSCROLL:
                hWndChild = (HWND)lParam;
                break;
        case WM_CTLCOLORBTN:
        case WM_CTLCOLORDLG:
        case WM_CTLCOLOREDIT:
        case WM_CTLCOLORLISTBOX:
        case WM_CTLCOLORMSGBOX:
        case WM_CTLCOLORSCROLLBAR:
        case WM_CTLCOLORSTATIC:
                hWndChild = (HWND)lParam;
                break;
        default:
                break;
        }

        if(hWndChild == NULL)
        {
                bHandled = FALSE;
                return 1;
        }

        ATLASSERT(::IsWindow(hWndChild));
        return ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
}

template <class TBase>
BOOL CWindowImplRoot< TBase >::DefaultReflectionHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult)
{
        switch(uMsg)
        {
        case OCM_COMMAND:
        case OCM_NOTIFY:
        case OCM_PARENTNOTIFY:
        case OCM_DRAWITEM:
        case OCM_MEASUREITEM:
        case OCM_COMPAREITEM:
        case OCM_DELETEITEM:
        case OCM_VKEYTOITEM:
        case OCM_CHARTOITEM:
        case OCM_HSCROLL:
        case OCM_VSCROLL:
        case OCM_CTLCOLORBTN:
        case OCM_CTLCOLORDLG:
        case OCM_CTLCOLOREDIT:
        case OCM_CTLCOLORLISTBOX:
        case OCM_CTLCOLORMSGBOX:
        case OCM_CTLCOLORSCROLLBAR:
        case OCM_CTLCOLORSTATIC:
                lResult = ::DefWindowProc(hWnd, uMsg - OCM__BASE, wParam, lParam);
                return TRUE;
        default:
                break;
        }
        return FALSE;
}

template <class TBase = CWindow, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CWindowImplBaseT : public CWindowImplRoot< TBase >
{
public:
        WNDPROC m_pfnSuperWindowProc;

        CWindowImplBaseT() : m_pfnSuperWindowProc(::DefWindowProc)
        {}

        static DWORD GetWndStyle(DWORD dwStyle)
        {
                return TWinTraits::GetWndStyle(dwStyle);
        }
        static DWORD GetWndExStyle(DWORD dwExStyle)
        {
                return TWinTraits::GetWndExStyle(dwExStyle);
        }

        virtual WNDPROC GetWindowProc()
        {
                return WindowProc;
        }
        static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
        static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
        HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName,
                        DWORD dwStyle, DWORD dwExStyle, UINT nID, ATOM atom, LPVOID lpCreateParam = NULL);
        BOOL DestroyWindow()
        {
                ATLASSERT(::IsWindow(m_hWnd));
                return ::DestroyWindow(m_hWnd);
        }
        BOOL SubclassWindow(HWND hWnd);
        HWND UnsubclassWindow(BOOL bForce = FALSE);

        LRESULT DefWindowProc()
        {
                const MSG* pMsg = m_pCurrentMsg;
                LRESULT lRes = 0;
                if (pMsg != NULL)
                        lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
                return lRes;
        }

        LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
#ifdef STRICT
                return ::CallWindowProc(m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#else
                return ::CallWindowProc((FARPROC)m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#endif
        }

        virtual void OnFinalMessage(HWND /*hWnd*/)
        {
                // override to do something, if needed
        }
};

typedef CWindowImplBaseT<CWindow>        CWindowImplBase;

template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)_Module.ExtractCreateWndData();
        ATLASSERT(pThis != NULL);
        pThis->m_hWnd = hWnd;
        pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);
        WNDPROC pProc = (WNDPROC)(pThis->m_thunk.thunk.pThunk);
        WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)pProc);
#ifdef _DEBUG
        // check if somebody has subclassed us already since we discard it
        if(pOldProc != StartWindowProc)
                ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
#else
        pOldProc;        // avoid unused warning
#endif
        return pProc(hWnd, uMsg, wParam, lParam);
}

template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
        // set a ptr to this message and save the old value
        MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
        const MSG* pOldMsg = pThis->m_pCurrentMsg;
        pThis->m_pCurrentMsg = &msg;
        // pass to the message map to process
        LRESULT lRes;
        BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
        // restore saved value for the current message
        ATLASSERT(pThis->m_pCurrentMsg == &msg);
        pThis->m_pCurrentMsg = pOldMsg;
        // do the default processing if message was not handled
        if(!bRet)
        {
                if(uMsg != WM_NCDESTROY)
                        lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
                else
                {
                        // unsubclass, if needed
                        LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
                        lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
                        if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
                                ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
                        // clear out window handle
                        HWND L_hWnd = pThis->m_hWnd;
                        pThis->m_hWnd = NULL;
                        // clean up after window is destroyed
                        pThis->OnFinalMessage(L_hWnd);
                }
        }
        return lRes;
}

template <class TBase, class TWinTraits>
HWND CWindowImplBaseT< TBase, TWinTraits >::Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName,
                DWORD dwStyle, DWORD dwExStyle, UINT nID, ATOM atom, LPVOID lpCreateParam)
{
        ATLASSERT(m_hWnd == NULL);

        if(atom == 0)
                return NULL;

        _Module.AddCreateWndData(&m_thunk.cd, this);

        if(nID == 0 && (dwStyle & WS_CHILD))
#if _ATL_VER > 0x0300
                nID = _Module.GetNextWindowID();
#else
        nID = (UINT)this;
#endif

        HWND hWnd = ::CreateWindowEx(dwExStyle, (LPCTSTR)(LONG_PTR)MAKELONG(atom, 0), szWindowName,
                dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
                rcPos.bottom - rcPos.top, hWndParent, (HMENU)(DWORD_PTR)nID,
                _Module.GetModuleInstance(), lpCreateParam);

        ATLASSERT(m_hWnd == hWnd);

        return hWnd;
}

template <class TBase, class TWinTraits>
BOOL CWindowImplBaseT< TBase, TWinTraits >::SubclassWindow(HWND hWnd)
{
        ATLASSERT(m_hWnd == NULL);
        ATLASSERT(::IsWindow(hWnd));
        m_thunk.Init(GetWindowProc(), this);
        WNDPROC pProc = (WNDPROC)(m_thunk.thunk.pThunk);
        WNDPROC pfnWndProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)pProc);
        if(pfnWndProc == NULL)
                return FALSE;
        m_pfnSuperWindowProc = pfnWndProc;
        m_hWnd = hWnd;
        return TRUE;
}

// Use only if you want to subclass before window is destroyed,
// WindowProc will automatically subclass when  window goes away
template <class TBase, class TWinTraits>
HWND CWindowImplBaseT< TBase, TWinTraits >::UnsubclassWindow(BOOL bForce /*= FALSE*/)
{
        ATLASSERT(m_hWnd != NULL);

        WNDPROC pOurProc = (WNDPROC)(m_thunk.thunk.pThunk);
        WNDPROC pActiveProc = (WNDPROC)::GetWindowLongPtr(m_hWnd, GWLP_WNDPROC);

        HWND hWnd = NULL;
        if (bForce || pOurProc == pActiveProc)
        {
                if(!::SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_pfnSuperWindowProc))
                        return NULL;

                m_pfnSuperWindowProc = ::DefWindowProc;
                hWnd = m_hWnd;
                m_hWnd = NULL;
        }
        return hWnd;
}

template <class T, class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits >
{
public:
        DECLARE_WND_CLASS(NULL)

        HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
                        DWORD dwStyle = 0, DWORD dwExStyle = 0,
                        UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                if (T::GetWndClassInfo().m_lpszOrigName == NULL)
                        T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
                ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);

                dwStyle = T::GetWndStyle(dwStyle);
                dwExStyle = T::GetWndExStyle(dwExStyle);

                return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName,
                        dwStyle, dwExStyle, nID, atom, lpCreateParam);
        }
};

/////////////////////////////////////////////////////////////////////////////
// CDialogImpl - Implements a dialog box

template <class TBase = CWindow>
class ATL_NO_VTABLE CDialogImplBaseT : public CWindowImplRoot< TBase >
{
public:
	virtual DLGPROC GetDialogProc()
	{
		return DialogProc;
	}
	static INT_PTR CALLBACK StartDialogProc(HWND hWnd, UINT uMsg,
		WPARAM wParam, LPARAM lParam);
	static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	BOOL MapDialogRect(LPRECT lpRect)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return ::MapDialogRect(m_hWnd, lpRect);
	}
	virtual void OnFinalMessage(HWND /*hWnd*/)
	{
		// override to do something, if needed
	}
	// has no meaning for a dialog, but needed for handlers that use it
	LRESULT DefWindowProc()
	{
		return 0;
	}
};

template <class TBase>
INT_PTR CALLBACK CDialogImplBaseT< TBase >::StartDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        CDialogImplBaseT< TBase >* pThis = (CDialogImplBaseT< TBase >*)_Module.ExtractCreateWndData();
        ATLASSERT(pThis != NULL);
        pThis->m_hWnd = hWnd;
        pThis->m_thunk.Init((WNDPROC)pThis->GetDialogProc(), pThis);
        DLGPROC pProc = (DLGPROC)(pThis->m_thunk.thunk.pThunk);
        DLGPROC pOldProc = (DLGPROC)::SetWindowLongPtr(hWnd, DWLP_DLGPROC, (LPARAM)pProc);
#ifdef _DEBUG
        // check if somebody has subclassed us already since we discard it
        if(pOldProc != StartDialogProc)
                ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
#else
        pOldProc;        // avoid unused warning
#endif
        return pProc(hWnd, uMsg, wParam, lParam);
}

template <class TBase>
INT_PTR CALLBACK CDialogImplBaseT< TBase >::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        CDialogImplBaseT< TBase >* pThis = (CDialogImplBaseT< TBase >*)hWnd;
        // set a ptr to this message and save the old value
        MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
        const MSG* pOldMsg = pThis->m_pCurrentMsg;
        pThis->m_pCurrentMsg = &msg;
        // pass to the message map to process
        LRESULT lRes;
        BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
        // restore saved value for the current message
        ATLASSERT(pThis->m_pCurrentMsg == &msg);
        pThis->m_pCurrentMsg = pOldMsg;
        // set result if message was handled
        if(bRet)
        {
                switch (uMsg)
                {
                case WM_COMPAREITEM:
                case WM_VKEYTOITEM:
                case WM_CHARTOITEM:
                case WM_INITDIALOG:
                case WM_QUERYDRAGICON:
                case WM_CTLCOLORMSGBOX:
                case WM_CTLCOLOREDIT:
                case WM_CTLCOLORLISTBOX:
                case WM_CTLCOLORBTN:
                case WM_CTLCOLORDLG:
                case WM_CTLCOLORSCROLLBAR:
                case WM_CTLCOLORSTATIC:
                        return lRes;
                        break;
                }
                ::SetWindowLongPtr(pThis->m_hWnd, DWLP_MSGRESULT, lRes);
                return TRUE;
        }
        if(uMsg == WM_NCDESTROY)
        {
                // clear out window handle
                HWND hWnd = pThis->m_hWnd;
                pThis->m_hWnd = NULL;
                // clean up after dialog is destroyed
                pThis->OnFinalMessage(hWnd);
        }
        return FALSE;
}

typedef CDialogImplBaseT<CWindow>        CDialogImplBase;

template <class T, class TBase /* = CWindow */>
class ATL_NO_VTABLE CDialogImpl : public CDialogImplBaseT< TBase >
{
public:
#ifdef _DEBUG
        bool m_bModal;
        CDialogImpl() : m_bModal(false) { }
#endif //_DEBUG
        // modal dialogs
        INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
        {
                ATLASSERT(m_hWnd == NULL);
                _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT< TBase >*)this);
#ifdef _DEBUG
                m_bModal = true;
#endif //_DEBUG
		return ::DialogBoxParam(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::IDD),
					hWndParent, T::StartDialogProc, dwInitParam);
	}
	BOOL EndDialog(INT_PTR nRetCode)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(m_bModal);	// must be a modal dialog
		return ::EndDialog(m_hWnd, nRetCode);
	}
	// modeless dialogs
	HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
	{
		ATLASSERT(m_hWnd == NULL);
		_Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT< TBase >*)this);
#ifdef _DEBUG
                m_bModal = false;
#endif //_DEBUG
		HWND hWnd = ::CreateDialogParam(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::IDD),
					hWndParent, T::StartDialogProc, dwInitParam);
		ATLASSERT(m_hWnd == hWnd);
		return hWnd;
	}
	// for CComControl
	HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)
	{
		return Create(hWndParent, dwInitParam);
	}
	BOOL DestroyWindow()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(!m_bModal);	// must not be a modal dialog
		return ::DestroyWindow(m_hWnd);
	}
};

/////////////////////////////////////////////////////////////////////////////
// CAxDialogImpl - Implements a dialog box that hosts ActiveX controls

#ifndef _ATL_NO_HOSTING

template <class T, class TBase /* = CWindow */>
class ATL_NO_VTABLE CAxDialogImpl : public CDialogImplBaseT< TBase >
{
public:
#ifdef _DEBUG
        bool m_bModal;
        CAxDialogImpl() : m_bModal(false) { }
#endif //_DEBUG
        // modal dialogs
        INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
        {
                ATLASSERT(m_hWnd == NULL);
                _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT< TBase >*)this);
#ifdef _DEBUG
                m_bModal = true;
#endif //_DEBUG
		return AtlAxDialogBox(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::IDD),
					hWndParent, T::StartDialogProc, dwInitParam);
	}
	BOOL EndDialog(int nRetCode)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(m_bModal);	// must be a modal dialog
		return ::EndDialog(m_hWnd, nRetCode);
	}
	// modeless dialogs
	HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
	{
		ATLASSERT(m_hWnd == NULL);
		_Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT< TBase >*)this);
#ifdef _DEBUG
                m_bModal = false;
#endif //_DEBUG
		HWND hWnd = AtlAxCreateDialog(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::IDD),
					hWndParent, T::StartDialogProc, dwInitParam);
		ATLASSERT(m_hWnd == hWnd);
		return hWnd;
	}
	// for CComControl
	HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)
	{
		return Create(hWndParent, dwInitParam);
	}
	BOOL DestroyWindow()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(!m_bModal);	// must not be a modal dialog
		return ::DestroyWindow(m_hWnd);
	}
};

#endif //_ATL_NO_HOSTING

/////////////////////////////////////////////////////////////////////////////
// CSimpleDialog - Prebuilt modal dialog that uses standard buttons

template <WORD t_wDlgTemplateID, BOOL t_bCenter /* = TRUE */>
class CSimpleDialog : public CDialogImplBase
{
public:
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT(m_hWnd == NULL);
		_Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBase*)this);
		INT_PTR nRet = ::DialogBox(_Module.GetResourceInstance(),
			MAKEINTRESOURCE(t_wDlgTemplateID), hWndParent, StartDialogProc);
		m_hWnd = NULL;
		return nRet;
	}

        typedef CSimpleDialog<t_wDlgTemplateID, t_bCenter>        thisClass;
        BEGIN_MSG_MAP(thisClass)
                MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
                COMMAND_RANGE_HANDLER(IDOK, IDNO, OnCloseCmd)
        END_MSG_MAP()

        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
        {
                if(t_bCenter)
                        CenterWindow(GetParent());
                return TRUE;
        }

        LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
        {
                ::EndDialog(m_hWnd, wID);
                return 0;
        }
};

/////////////////////////////////////////////////////////////////////////////
// CContainedWindow - Implements a contained window

template <class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
class CContainedWindowT : public TBase
{
public:
        CWndProcThunk m_thunk;
        LPCTSTR m_lpszClassName;
        WNDPROC m_pfnSuperWindowProc;
        CMessageMap* m_pObject;
        DWORD m_dwMsgMapID;
        const MSG* m_pCurrentMsg;

        // If you use this constructor you must supply
        // the Window Class Name, Object* and Message Map ID
        // Later to the Create call
        CContainedWindowT() : m_pCurrentMsg(NULL)
        { }

        CContainedWindowT(LPTSTR lpszClassName, CMessageMap* pObject, DWORD dwMsgMapID = 0)
                : m_lpszClassName(lpszClassName),
                m_pfnSuperWindowProc(::DefWindowProc),
                m_pObject(pObject), m_dwMsgMapID(dwMsgMapID),
                m_pCurrentMsg(NULL)
        { }

        CContainedWindowT(CMessageMap* pObject, DWORD dwMsgMapID = 0)
                : m_lpszClassName(TBase::GetWndClassName()),
                m_pfnSuperWindowProc(::DefWindowProc),
                m_pObject(pObject), m_dwMsgMapID(dwMsgMapID),
                m_pCurrentMsg(NULL)
        { }

        void SwitchMessageMap(DWORD dwMsgMapID)
        {
                m_dwMsgMapID = dwMsgMapID;
        }

        const MSG* GetCurrentMessage() const
        {
                return m_pCurrentMsg;
        }

        LRESULT DefWindowProc()
        {
                const MSG* pMsg = m_pCurrentMsg;
                LRESULT lRes = 0;
                if (pMsg != NULL)
                        lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
                return lRes;
        }

        LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
#ifdef STRICT
                return ::CallWindowProc(m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#else
                return ::CallWindowProc((FARPROC)m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#endif
        }
        static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg,
                WPARAM wParam, LPARAM lParam)
        {
                CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)_Module.ExtractCreateWndData();
                ATLASSERT(pThis != NULL);
                pThis->m_hWnd = hWnd;
                pThis->m_thunk.Init(WindowProc, pThis);
                WNDPROC pProc = (WNDPROC)(pThis->m_thunk.thunk.pThunk);
                WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
#ifdef _DEBUG
                // check if somebody has subclassed us already since we discard it
                if(pOldProc != StartWindowProc)
                        ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
#else
                pOldProc;        // avoid unused warning
#endif
                return pProc(hWnd, uMsg, wParam, lParam);
        }

        static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
                CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)hWnd;
                ATLASSERT(pThis->m_hWnd != NULL);
                ATLASSERT(pThis->m_pObject != NULL);
                // set a ptr to this message and save the old value
                MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
                const MSG* pOldMsg = pThis->m_pCurrentMsg;
                pThis->m_pCurrentMsg = &msg;
                // pass to the message map to process
                LRESULT lRes;
                BOOL bRet = pThis->m_pObject->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, pThis->m_dwMsgMapID);
                // restore saved value for the current message
                ATLASSERT(pThis->m_pCurrentMsg == &msg);
                pThis->m_pCurrentMsg = pOldMsg;
                // do the default processing if message was not handled
                if(!bRet)
                {
                        if(uMsg != WM_NCDESTROY)
                                lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
                        else
                        {
                                // unsubclass, if needed
                                LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
                                lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
                                if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
                                        ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
                                // clear out window handle
                                pThis->m_hWnd = NULL;
                        }
                }
                return lRes;
        }

        ATOM RegisterWndSuperclass()
        {
                ATOM atom = 0;
                LPTSTR szBuff = (LPTSTR)_alloca((lstrlen(m_lpszClassName) + 14) * sizeof(TCHAR));

                WNDCLASSEX wc;
                wc.cbSize = sizeof(WNDCLASSEX);

                // Try global class
                if(!::GetClassInfoEx(NULL, m_lpszClassName, &wc))
                {
                        // try local class
                        if(!::GetClassInfoEx(_Module.GetModuleInstance(), m_lpszClassName, &wc))
                                return atom;
                }

                m_pfnSuperWindowProc = wc.lpfnWndProc;
                lstrcpy(szBuff, _T("ATL:"));
                lstrcat(szBuff, m_lpszClassName);                

                WNDCLASSEX wc1;
                wc1.cbSize = sizeof(WNDCLASSEX);
                atom = (ATOM)::GetClassInfoEx(_Module.GetModuleInstance(), szBuff, &wc1);

                if(atom == 0)   // register class
                {
                        wc.lpszClassName = szBuff;
                        wc.lpfnWndProc = StartWindowProc;
                        wc.hInstance = _Module.GetModuleInstance();
                        wc.style &= ~CS_GLOBALCLASS;        // we don't register global classes

                        atom = ::RegisterClassEx(&wc);
                }

                return atom;
        }
        HWND Create(CMessageMap* pObject, DWORD dwMsgMapID, HWND hWndParent, RECT* prcPos,
                LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0,
                UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                m_lpszClassName = TBase::GetWndClassName();
                m_pfnSuperWindowProc = ::DefWindowProc;
                m_pObject = pObject;
                m_dwMsgMapID = dwMsgMapID;
                return Create(hWndParent, prcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
        }

        HWND Create(LPCTSTR lpszClassName, CMessageMap* pObject, DWORD dwMsgMapID, HWND hWndParent, RECT* prcPos, LPCTSTR szWindowName = NULL,
                DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                m_lpszClassName = lpszClassName;
                m_pfnSuperWindowProc = ::DefWindowProc;
                m_pObject = pObject;
                m_dwMsgMapID = dwMsgMapID;
                return Create(hWndParent, prcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
        }


        // This function is Deprecated, use the version
        // which takes a RECT* instead
        HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
                DWORD dwStyle = 0, DWORD dwExStyle = 0,
                UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                return Create(hWndParent, &rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
        }

        HWND Create(HWND hWndParent, RECT* prcPos, LPCTSTR szWindowName = NULL,
                DWORD dwStyle = 0, DWORD dwExStyle = 0,
                UINT nID = 0, LPVOID lpCreateParam = NULL)
        {
                ATLASSERT(m_hWnd == NULL);

                ATOM atom = RegisterWndSuperclass();
                if(atom == 0)
                        return NULL;

                _Module.AddCreateWndData(&m_thunk.cd, this);

                dwStyle = TWinTraits::GetWndStyle(dwStyle);
                dwExStyle = TWinTraits::GetWndExStyle(dwExStyle);

                HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,
                                                                dwStyle,
                                                                prcPos->left, prcPos->top,
                                                                prcPos->right - prcPos->left,
                                                                prcPos->bottom - prcPos->top,
                                                                hWndParent, 
                                                                (nID == 0 && (dwStyle & WS_CHILD)) ? (HMENU)this : (HMENU)(DWORD_PTR)nID,
                                                                _Module.GetModuleInstance(), lpCreateParam);
                ATLASSERT(m_hWnd == hWnd);
                return hWnd;
        }

        BOOL SubclassWindow(HWND hWnd)
        {
                ATLASSERT(m_hWnd == NULL);
                ATLASSERT(::IsWindow(hWnd));

                m_thunk.Init(WindowProc, this);
                WNDPROC pProc = (WNDPROC)m_thunk.thunk.pThunk;
                WNDPROC pfnWndProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
                if(pfnWndProc == NULL)
                        return FALSE;
                m_pfnSuperWindowProc = pfnWndProc;
                m_hWnd = hWnd;
                return TRUE;
        }

        // Use only if you want to subclass before window is destroyed,
        // WindowProc will automatically subclass when  window goes away
        HWND UnsubclassWindow(BOOL bForce = FALSE)
        {
                ATLASSERT(m_hWnd != NULL);

                WNDPROC pOurProc = (WNDPROC)(m_thunk.thunk.pThunk);
                WNDPROC pActiveProc = (WNDPROC)::GetWindowLongPtr(m_hWnd, GWLP_WNDPROC);

                HWND hWnd = NULL;
                if (bForce || pOurProc == pActiveProc)
                {
                        if(!::SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_pfnSuperWindowProc))
                                return NULL;

                        m_pfnSuperWindowProc = ::DefWindowProc;
                        hWnd = m_hWnd;
                        m_hWnd = NULL;
                }
                return hWnd;
        }
};

typedef CContainedWindowT<CWindow>        CContainedWindow;

/////////////////////////////////////////////////////////////////////////////
// _DialogSizeHelper - helpers for calculating the size of a dialog template

class _DialogSizeHelper
{
public:
//local struct used for implementation
#pragma pack(push, 1)
        struct _ATL_DLGTEMPLATEEX
        {
                WORD dlgVer;
                WORD signature;
                DWORD helpID;
                DWORD exStyle;
                DWORD style;
                WORD cDlgItems;
                short x;
                short y;
                short cx;
                short cy;
        };
#pragma pack(pop)

        static void GetDialogSize(const DLGTEMPLATE* pTemplate, SIZE* pSize)
        {
                // If the dialog has a font we use it otherwise we default
                // to the system font.
                if (HasFont(pTemplate))
                {
                        TCHAR szFace[LF_FACESIZE];                                        
                        WORD  wFontSize = 0;
                        GetFont(pTemplate, szFace, &wFontSize);                
                        GetSizeInDialogUnits(pTemplate, pSize);
                        ConvertDialogUnitsToPixels(szFace, wFontSize, pSize);
                }
                else
                {
                        GetSizeInDialogUnits(pTemplate, pSize);
                        LONG nDlgBaseUnits = GetDialogBaseUnits();
                        pSize->cx = MulDiv(pSize->cx, LOWORD(nDlgBaseUnits), 4);
                        pSize->cy = MulDiv(pSize->cy, HIWORD(nDlgBaseUnits), 8);
                }
        }

        static void ConvertDialogUnitsToPixels(LPCTSTR pszFontFace, WORD wFontSize, SIZE* pSizePixel)
        {
                // Attempt to create the font to be used in the dialog box
                UINT cxSysChar, cySysChar;
                LOGFONT lf;
                HDC hDC = ::GetDC(NULL);
                int cxDlg = pSizePixel->cx;
                int cyDlg = pSizePixel->cy;

                ZeroMemory(&lf, sizeof(LOGFONT));
                lf.lfHeight = -MulDiv(wFontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
                lf.lfWeight = FW_NORMAL;
                lf.lfCharSet = DEFAULT_CHARSET;
                lstrcpyn(lf.lfFaceName, pszFontFace, sizeof lf.lfFaceName / sizeof lf.lfFaceName[0]);

                HFONT hNewFont = CreateFontIndirect(&lf);
                if (hNewFont != NULL)
                {
                        TEXTMETRIC  tm;
                        SIZE        size;
                        HFONT       hFontOld = (HFONT)SelectObject(hDC, hNewFont);
                        GetTextMetrics(hDC, &tm);
                        cySysChar = tm.tmHeight + tm.tmExternalLeading;
                        ::GetTextExtentPoint(hDC,
                                _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52,
                                &size);
                        cxSysChar = (size.cx + 26) / 52;
                        SelectObject(hDC, hFontOld);
                        DeleteObject(hNewFont);
                }
                else
                {
                        // Could not create the font so just use the system's values
                        cxSysChar = LOWORD(GetDialogBaseUnits());
                        cySysChar = HIWORD(GetDialogBaseUnits());
                }
                ::ReleaseDC(NULL, hDC);

                // Translate dialog units to pixels
                pSizePixel->cx = MulDiv(cxDlg, cxSysChar, 4);
                pSizePixel->cy = MulDiv(cyDlg, cySysChar, 8);
        }

        static BOOL IsDialogEx(const DLGTEMPLATE* pTemplate)
        {
                return ((_ATL_DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF;
        }

        static BOOL HasFont(const DLGTEMPLATE* pTemplate)
        {
                return (DS_SETFONT &
                        (IsDialogEx(pTemplate) ?
                                ((_ATL_DLGTEMPLATEEX*)pTemplate)->style : pTemplate->style));
        }

        static BYTE* GetFontSizeField(const DLGTEMPLATE* pTemplate)
        {
                BOOL bDialogEx = IsDialogEx(pTemplate);
                WORD* pw;

                if (bDialogEx)
                        pw = (WORD*)((_ATL_DLGTEMPLATEEX*)pTemplate + 1);
                else
                        pw = (WORD*)(pTemplate + 1);

                if (*pw == (WORD)-1)        // Skip menu name string or ordinal
                        pw += 2; // WORDs
                else
                        while(*pw++);

                if (*pw == (WORD)-1)        // Skip class name string or ordinal
                        pw += 2; // WORDs
                else
                        while(*pw++);

                while (*pw++);          // Skip caption string

                return (BYTE*)pw;
        }

        static BOOL GetFont(const DLGTEMPLATE* pTemplate, TCHAR* pszFace, WORD* pFontSize)
        {
                USES_CONVERSION;
                if (!HasFont(pTemplate))
                        return FALSE;

                BYTE* pb = GetFontSizeField(pTemplate);
                *pFontSize = *(WORD*)pb;
                // Skip over font attributes to get to the font name
                pb += sizeof(WORD) * (IsDialogEx(pTemplate) ? 3 : 1);
                
                _tcsncpy(pszFace, W2T((WCHAR*)pb), LF_FACESIZE);
                if (_tcslen(pszFace) >= LF_FACESIZE) 
                {        // NUL not appended
                        pszFace[LF_FACESIZE-1] = _T('\0');
                }
                return TRUE;
        }

        static void GetSizeInDialogUnits(const DLGTEMPLATE* pTemplate, SIZE* pSize)
        {
                if (IsDialogEx(pTemplate))
                {
                        pSize->cx = ((_ATL_DLGTEMPLATEEX*)pTemplate)->cx;
                        pSize->cy = ((_ATL_DLGTEMPLATEEX*)pTemplate)->cy;
                }
                else
                {
                        pSize->cx = pTemplate->cx;
                        pSize->cy = pTemplate->cy;
                }
        }
};

inline void AtlGetDialogSize(const DLGTEMPLATE* pTemplate, SIZE* pSize)
{
        _DialogSizeHelper::GetDialogSize(pTemplate, pSize);
}

}; //namespace ATL

#ifndef _ATL_DLL_IMPL
#ifndef _ATL_DLL
#define _ATLWIN_IMPL
#endif
#endif

#endif // __ATLWIN_H__

//All exports go here
#ifdef _ATLWIN_IMPL

#ifndef _ATL_DLL_IMPL
namespace ATL
{
#endif

ATLINLINE ATLAPI_(ATOM) AtlModuleRegisterWndClassInfoA(_ATL_MODULE* pM, _ATL_WNDCLASSINFOA* p, WNDPROC* pProc)
{                
        BOOL fFail = FALSE;
        if (p->m_atom == 0)
        {

                ::EnterCriticalSection(&pM->m_csWindowCreate);
                __try 
                {
                        if(p->m_atom == 0)
                        {
                                HINSTANCE hInst = pM->m_hInst;
                                if (p->m_lpszOrigName != NULL)
                                {
                                        ATLASSERT(pProc != NULL);
                                        LPCSTR lpsz = p->m_wc.lpszClassName;
                                        WNDPROC proc = p->m_wc.lpfnWndProc;

                                        WNDCLASSEXA wc;
                                        wc.cbSize = sizeof(WNDCLASSEX);
                                        // Try global class
                                        if(!::GetClassInfoExA(NULL, p->m_lpszOrigName, &wc))
                                        {
                                                // try process local
                                                if(!::GetClassInfoExA(_Module.GetModuleInstance(), p->m_lpszOrigName, &wc))
                                                {
                                                        fFail = TRUE;
                                                        __leave;
                                                }
                                        }
                                        memcpy(&p->m_wc, &wc, sizeof(WNDCLASSEX));
                                        p->pWndProc = p->m_wc.lpfnWndProc;
                                        p->m_wc.lpszClassName = lpsz;
                                        p->m_wc.lpfnWndProc = proc;
                                }
                                else
                                {
                                        p->m_wc.hCursor = ::LoadCursorA(p->m_bSystemCursor ? NULL : hInst,
                                                p->m_lpszCursorID);
                                }

                                p->m_wc.hInstance = hInst;
                                p->m_wc.style &= ~CS_GLOBALCLASS;        // we don't register global classes
                                if (p->m_wc.lpszClassName == NULL)
                                {
#ifdef _WIN64       // %p isn't available on Win2k/Win9x
                                        wsprintfA(p->m_szAutoName, "ATL:%p", &p->m_wc);
#else
                                        wsprintfA(p->m_szAutoName, "ATL:%8.8X", PtrToUlong(&p->m_wc));
#endif
                                        p->m_wc.lpszClassName = p->m_szAutoName;
                                }
                                WNDCLASSEXA wcTemp;
                                memcpy(&wcTemp, &p->m_wc, sizeof(WNDCLASSEXW));
                                p->m_atom = (ATOM)::GetClassInfoExA(p->m_wc.hInstance, p->m_wc.lpszClassName, &wcTemp);
                                if (p->m_atom == 0)
                                        p->m_atom = ::RegisterClassExA(&p->m_wc);
                        }
                }
                __finally 
                {
                        ::LeaveCriticalSection(&pM->m_csWindowCreate);
                }
        }

        if (fFail)
        {
                return 0;
        }

        if (p->m_lpszOrigName != NULL)
        {
                ATLASSERT(pProc != NULL);
                ATLASSERT(p->pWndProc != NULL);
                *pProc = p->pWndProc;
        }
        return p->m_atom;
}

ATLINLINE ATLAPI_(ATOM) AtlModuleRegisterWndClassInfoW(_ATL_MODULE* pM, _ATL_WNDCLASSINFOW* p, WNDPROC* pProc)
{
        BOOL fFail = FALSE;

        if (p->m_atom == 0)
        {
                ::EnterCriticalSection(&pM->m_csWindowCreate);        
                __try
                {
                        if(p->m_atom == 0)
                        {
                                HINSTANCE hInst = pM->m_hInst;
                                if (p->m_lpszOrigName != NULL)
                                {
                                        ATLASSERT(pProc != NULL);
                                        LPCWSTR lpsz = p->m_wc.lpszClassName;
                                        WNDPROC proc = p->m_wc.lpfnWndProc;

                                        WNDCLASSEXW wc;
                                        wc.cbSize = sizeof(WNDCLASSEX);
                                        // Try global class
                                        if(!::GetClassInfoExW(NULL, p->m_lpszOrigName, &wc))
                                        {
                                                // try process local
                                                if(!::GetClassInfoExW(_Module.GetModuleInstance(), p->m_lpszOrigName, &wc))
                                                {
                                                        fFail = TRUE;
                                                        __leave;
                                                }
                                        }
                                        memcpy(&p->m_wc, &wc, sizeof(WNDCLASSEX));
                                        p->pWndProc = p->m_wc.lpfnWndProc;
                                        p->m_wc.lpszClassName = lpsz;
                                        p->m_wc.lpfnWndProc = proc;
                                }
                                else
                                {
                                        p->m_wc.hCursor = ::LoadCursorW(p->m_bSystemCursor ? NULL : hInst,
                                                p->m_lpszCursorID);
                                }

                                p->m_wc.hInstance = hInst;
                                p->m_wc.style &= ~CS_GLOBALCLASS;        // we don't register global classes
                                if (p->m_wc.lpszClassName == NULL)
                                {
#ifdef _WIN64       // %p isn't available on Win2k/Win9x
                                        wsprintfW(p->m_szAutoName, L"ATL:%p", &p->m_wc);
#else
                                        wsprintfW(p->m_szAutoName, L"ATL:%8.8X", PtrToUlong(&p->m_wc));
#endif
                                        p->m_wc.lpszClassName = p->m_szAutoName;
                                }
                                WNDCLASSEXW wcTemp;
                                memcpy(&wcTemp, &p->m_wc, sizeof(WNDCLASSEXW));
                                p->m_atom = (ATOM)::GetClassInfoExW(p->m_wc.hInstance, p->m_wc.lpszClassName, &wcTemp);
                                if (p->m_atom == 0)
                                        p->m_atom = ::RegisterClassExW(&p->m_wc);
                        }
                }
                __finally
                {
                        ::LeaveCriticalSection(&pM->m_csWindowCreate);
                }
        }

        if (fFail)
        {
                return 0;
        }

        if (p->m_lpszOrigName != NULL)
        {
                ATLASSERT(pProc != NULL);
                ATLASSERT(p->pWndProc != NULL);
                *pProc = p->pWndProc;
        }
        return p->m_atom;
}

ATLINLINE ATLAPI_(HDC) AtlCreateTargetDC(HDC hdc, DVTARGETDEVICE* ptd)
{
        USES_CONVERSION;

        // cases  hdc, ptd, hdc is metafile, hic
//  NULL,    NULL,  n/a,    Display
//  NULL,   !NULL,  n/a,    ptd
//  !NULL,   NULL,  FALSE,  hdc
//  !NULL,   NULL,  TRUE,   display
//  !NULL,  !NULL,  FALSE,  ptd
//  !NULL,  !NULL,  TRUE,   ptd

        if (ptd != NULL)
        {
                LPDEVMODEOLE lpDevMode;
                LPOLESTR lpszDriverName;
                LPOLESTR lpszDeviceName;
                LPOLESTR lpszPortName;

                if (ptd->tdExtDevmodeOffset == 0)
                        lpDevMode = NULL;
                else
                        lpDevMode  = (LPDEVMODEOLE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);

                lpszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset);
                lpszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset);
                lpszPortName   = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);
                
                return ::CreateDC(OLE2CT(lpszDriverName), OLE2CT(lpszDeviceName),
                        OLE2CT(lpszPortName), DEVMODEOLE2T(lpDevMode));
        }
        else if (hdc == NULL || GetDeviceCaps(hdc, TECHNOLOGY) == DT_METAFILE)
                return ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
        else
                return hdc;
}

ATLINLINE ATLAPI_(void) AtlHiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix)
{
        int nPixelsPerInchX;    // Pixels per logical inch along width
        int nPixelsPerInchY;    // Pixels per logical inch along height

        HDC hDCScreen = GetDC(NULL);
        ATLASSERT(hDCScreen != NULL);
        if (hDCScreen != NULL)
        {
                nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
                nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
                ReleaseDC(NULL, hDCScreen);
        }
        else
        {
                nPixelsPerInchX = 1;
                nPixelsPerInchY = 1;
        }

        lpSizeInPix->cx = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cx, nPixelsPerInchX);
        lpSizeInPix->cy = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cy, nPixelsPerInchY);
}

ATLINLINE ATLAPI_(void) AtlPixelToHiMetric(const SIZEL * lpSizeInPix, LPSIZEL lpSizeInHiMetric)
{
        int nPixelsPerInchX;    // Pixels per logical inch along width
        int nPixelsPerInchY;    // Pixels per logical inch along height

        HDC hDCScreen = GetDC(NULL);
    if (hDCScreen) {
            nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
            nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
            ReleaseDC(NULL, hDCScreen);
    } else {
        nPixelsPerInchX = nPixelsPerInchY = 1;
    }

        lpSizeInHiMetric->cx = MAP_PIX_TO_LOGHIM(lpSizeInPix->cx, nPixelsPerInchX);
        lpSizeInHiMetric->cy = MAP_PIX_TO_LOGHIM(lpSizeInPix->cy, nPixelsPerInchY);
}


#ifndef _ATL_DLL_IMPL
}; //namespace ATL
#endif

//Prevent pulling in second time
#undef _ATLWIN_IMPL

#endif // _ATLWIN_IMPL