--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLAPP_H__
+#define __ATLAPP_H__
+
+#pragma once
+
+#ifndef __cplusplus
+ #error WTL requires C++ compilation (use a .cpp suffix)
+#endif
+
+#ifndef __ATLBASE_H__
+ #error atlapp.h requires atlbase.h to be included first
+#endif
+
+#ifndef _WIN32_WCE
+ #if (WINVER < 0x0400)
+ #error WTL requires Windows version 4.0 or higher
+ #endif
+
+ #if (_WIN32_IE < 0x0300)
+ #error WTL requires IE version 3.0 or higher
+ #endif
+#endif
+
+#ifdef _ATL_NO_COMMODULE
+ #error WTL requires that _ATL_NO_COMMODULE is not defined
+#endif
+
+#if (_ATL_VER >= 0x0900) && defined(_ATL_MIN_CRT)
+ #error _ATL_MIN_CRT is not supported with ATL 9.0 and higher
+#endif
+
+#if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT)
+ #pragma message("Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT")
+#endif
+
+#include <limits.h>
+#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE)
+ #include <process.h> // for _beginthreadex
+#endif
+
+#if (_ATL_VER < 0x0800) && !defined(_DEBUG)
+ #include <stdio.h>
+#endif
+
+#include <commctrl.h>
+#ifndef _WIN32_WCE
+ #pragma comment(lib, "comctl32.lib")
+#endif
+
+#ifndef _WIN32_WCE
+ #include "atlres.h"
+#else // CE specific
+ #include "atlresce.h"
+#endif // _WIN32_WCE
+
+// We need to disable this warning because of template class arguments
+#pragma warning(disable: 4127)
+
+#if (_ATL_VER >= 0x0900) && !defined(_SECURE_ATL)
+ #define _SECURE_ATL 1
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// WTL version number
+
+#define _WTL_VER 0x0810
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CMessageFilter
+// CIdleHandler
+// CMessageLoop
+//
+// CAppModule
+// CServerAppModule
+//
+// CRegKeyEx
+//
+// Global functions:
+// AtlGetDefaultGuiFont()
+// AtlCreateControlFont()
+// AtlCreateBoldFont()
+// AtlInitCommonControls()
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global support for Windows CE
+
+#ifdef _WIN32_WCE
+
+#ifndef SW_SHOWDEFAULT
+ #define SW_SHOWDEFAULT SW_SHOWNORMAL
+#endif // !SW_SHOWDEFAULT
+
+// These get's OR-ed in a constant and will have no effect.
+// Defining them reduces the number of #ifdefs required for CE.
+#define LR_DEFAULTSIZE 0
+#define LR_LOADFROMFILE 0
+
+#ifndef SM_CXCURSOR
+ #define SM_CXCURSOR 13
+#endif
+#ifndef SM_CYCURSOR
+ #define SM_CYCURSOR 14
+#endif
+
+inline BOOL IsMenu(HMENU hMenu)
+{
+ MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
+ ::SetLastError(0);
+ BOOL bRet = ::GetMenuItemInfo(hMenu, 0, TRUE, &mii);
+ if(!bRet)
+ bRet = (::GetLastError() != ERROR_INVALID_MENU_HANDLE) ? TRUE : FALSE;
+ return bRet;
+}
+
+#if (_WIN32_WCE >= 410)
+extern "C" void WINAPI ListView_SetItemSpacing(HWND hwndLV, int iHeight);
+#endif // (_WIN32_WCE >= 410)
+
+inline int MulDiv(IN int nNumber, IN int nNumerator, IN int nDenominator)
+{
+ __int64 multiple = nNumber * nNumerator;
+ return static_cast<int>(multiple / nDenominator);
+}
+
+#if (_ATL_VER >= 0x0800)
+
+#ifndef _WTL_KEEP_WS_OVERLAPPEDWINDOW
+ #ifdef WS_OVERLAPPEDWINDOW
+ #undef WS_OVERLAPPEDWINDOW
+ #define WS_OVERLAPPEDWINDOW 0
+ #endif // WS_OVERLAPPEDWINDOW
+#endif // !_WTL_KEEP_WS_OVERLAPPEDWINDOW
+
+#ifndef RDW_FRAME
+ #define RDW_FRAME 0
+#endif // !RDW_FRAME
+
+#ifndef WM_WINDOWPOSCHANGING
+ #define WM_WINDOWPOSCHANGING 0
+#endif // !WM_WINDOWPOSCHANGING
+
+#define FreeResource(x)
+#define UnlockResource(x)
+
+namespace ATL
+{
+ inline HRESULT CComModule::RegisterClassObjects(DWORD /*dwClsContext*/, DWORD /*dwFlags*/) throw()
+ { return E_NOTIMPL; }
+ inline HRESULT CComModule::RevokeClassObjects() throw()
+ { return E_NOTIMPL; }
+}; // namespace ATL
+
+#ifndef lstrlenW
+ #define lstrlenW (int)ATL::lstrlenW
+#endif // lstrlenW
+
+inline int WINAPI lstrlenA(LPCSTR lpszString)
+{ return ATL::lstrlenA(lpszString); }
+
+#ifdef lstrcpyn
+ #undef lstrcpyn
+ #define lstrcpyn ATL::lstrcpynW
+#endif // lstrcpyn
+
+#ifndef SetWindowLongPtrW
+ inline LONG_PTR tmp_SetWindowLongPtrW( HWND hWnd, int nIndex, LONG_PTR dwNewLong )
+ {
+ return( ::SetWindowLongW( hWnd, nIndex, LONG( dwNewLong ) ) );
+ }
+ #define SetWindowLongPtrW tmp_SetWindowLongPtrW
+#endif
+
+#ifndef GetWindowLongPtrW
+ inline LONG_PTR tmp_GetWindowLongPtrW( HWND hWnd, int nIndex )
+ {
+ return( ::GetWindowLongW( hWnd, nIndex ) );
+ }
+ #define GetWindowLongPtrW tmp_GetWindowLongPtrW
+#endif
+
+#ifndef LongToPtr
+ #define LongToPtr(x) ((void*)x)
+#endif
+
+#ifndef PtrToInt
+ #define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#endif
+
+#else // !(_ATL_VER >= 0x0800)
+
+#ifdef lstrlenW
+ #undef lstrlenW
+ #define lstrlenW (int)::wcslen
+#endif // lstrlenW
+
+#define lstrlenA (int)strlen
+
+#ifndef lstrcpyn
+ inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength)
+ {
+ if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0)
+ return NULL;
+ int nLen = min(lstrlen(lpstrSrc), nLength - 1);
+ LPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR));
+ lpstrDest[nLen] = 0;
+ return lpstrRet;
+ }
+#endif // !lstrcpyn
+
+#ifndef lstrcpynW
+ inline LPWSTR lstrcpynW(LPWSTR lpstrDest, LPCWSTR lpstrSrc, int nLength)
+ {
+ return lstrcpyn(lpstrDest, lpstrSrc, nLength); // WinCE is Unicode only
+ }
+#endif // !lstrcpynW
+
+#ifndef lstrcpynA
+ inline LPSTR lstrcpynA(LPSTR lpstrDest, LPCSTR lpstrSrc, int nLength)
+ {
+ if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0)
+ return NULL;
+ int nLen = min(lstrlenA(lpstrSrc), nLength - 1);
+ LPSTR lpstrRet = (LPSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(char));
+ lpstrDest[nLen] = 0;
+ return lpstrRet;
+ }
+#endif // !lstrcpyn
+
+#ifdef TrackPopupMenu
+ #undef TrackPopupMenu
+#endif // TrackPopupMenu
+
+#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \
+static CWndClassInfo& GetWndClassInfo() \
+{ \
+ static CWndClassInfo wc = \
+ { \
+ { style, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
+ }; \
+ return wc; \
+}
+
+#ifndef _MAX_FNAME
+ #define _MAX_FNAME _MAX_PATH
+#endif // _MAX_FNAME
+
+#if (_WIN32_WCE < 400)
+ #define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i)))
+#endif // (_WIN32_WCE < 400)
+
+#if (_WIN32_WCE < 410)
+ #define WHEEL_PAGESCROLL (UINT_MAX)
+ #define WHEEL_DELTA 120
+#endif // (_WIN32_WCE < 410)
+
+#ifdef DrawIcon
+ #undef DrawIcon
+#endif
+
+#ifndef VARCMP_LT
+ #define VARCMP_LT 0
+#endif
+#ifndef VARCMP_EQ
+ #define VARCMP_EQ 1
+#endif
+#ifndef VARCMP_GT
+ #define VARCMP_GT 2
+#endif
+#ifndef VARCMP_NULL
+ #define VARCMP_NULL 3
+#endif
+
+#ifndef RDW_ALLCHILDREN
+ #define RDW_ALLCHILDREN 0
+#endif
+
+#endif // !(_ATL_VER >= 0x0800)
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global support for using original VC++ 6.0 headers with WTL
+
+#ifndef _ATL_NO_OLD_HEADERS_WIN64
+#if !defined(_WIN64) && (_ATL_VER < 0x0700)
+
+ #ifndef PSM_INSERTPAGE
+ #define PSM_INSERTPAGE (WM_USER + 119)
+ #endif // !PSM_INSERTPAGE
+
+ #ifndef GetClassLongPtr
+ #define GetClassLongPtrA GetClassLongA
+ #define GetClassLongPtrW GetClassLongW
+ #ifdef UNICODE
+ #define GetClassLongPtr GetClassLongPtrW
+ #else
+ #define GetClassLongPtr GetClassLongPtrA
+ #endif // !UNICODE
+ #endif // !GetClassLongPtr
+
+ #ifndef GCLP_HICONSM
+ #define GCLP_HICONSM (-34)
+ #endif // !GCLP_HICONSM
+
+ #ifndef GetWindowLongPtr
+ #define GetWindowLongPtrA GetWindowLongA
+ #define GetWindowLongPtrW GetWindowLongW
+ #ifdef UNICODE
+ #define GetWindowLongPtr GetWindowLongPtrW
+ #else
+ #define GetWindowLongPtr GetWindowLongPtrA
+ #endif // !UNICODE
+ #endif // !GetWindowLongPtr
+
+ #ifndef SetWindowLongPtr
+ #define SetWindowLongPtrA SetWindowLongA
+ #define SetWindowLongPtrW SetWindowLongW
+ #ifdef UNICODE
+ #define SetWindowLongPtr SetWindowLongPtrW
+ #else
+ #define SetWindowLongPtr SetWindowLongPtrA
+ #endif // !UNICODE
+ #endif // !SetWindowLongPtr
+
+ #ifndef GWLP_WNDPROC
+ #define GWLP_WNDPROC (-4)
+ #endif
+ #ifndef GWLP_HINSTANCE
+ #define GWLP_HINSTANCE (-6)
+ #endif
+ #ifndef GWLP_HWNDPARENT
+ #define GWLP_HWNDPARENT (-8)
+ #endif
+ #ifndef GWLP_USERDATA
+ #define GWLP_USERDATA (-21)
+ #endif
+ #ifndef GWLP_ID
+ #define GWLP_ID (-12)
+ #endif
+
+ #ifndef DWLP_MSGRESULT
+ #define DWLP_MSGRESULT 0
+ #endif
+
+ typedef long LONG_PTR;
+ typedef unsigned long ULONG_PTR;
+ typedef ULONG_PTR DWORD_PTR;
+
+ #ifndef HandleToUlong
+ #define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) )
+ #endif
+ #ifndef HandleToLong
+ #define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+ #endif
+ #ifndef LongToHandle
+ #define LongToHandle( h) ((HANDLE)(LONG_PTR) (h))
+ #endif
+ #ifndef PtrToUlong
+ #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+ #endif
+ #ifndef PtrToLong
+ #define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+ #endif
+ #ifndef PtrToUint
+ #define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+ #endif
+ #ifndef PtrToInt
+ #define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+ #endif
+ #ifndef PtrToUshort
+ #define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+ #endif
+ #ifndef PtrToShort
+ #define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+ #endif
+ #ifndef IntToPtr
+ #define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i))
+ #endif
+ #ifndef UIntToPtr
+ #define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui))
+ #endif
+ #ifndef LongToPtr
+ #define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l))
+ #endif
+ #ifndef ULongToPtr
+ #define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul))
+ #endif
+
+#endif // !defined(_WIN64) && (_ATL_VER < 0x0700)
+#endif // !_ATL_NO_OLD_HEADERS_WIN64
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global support for SecureHelper functions
+
+#ifndef _TRUNCATE
+ #define _TRUNCATE ((size_t)-1)
+#endif
+
+#ifndef _ERRCODE_DEFINED
+ #define _ERRCODE_DEFINED
+ typedef int errno_t;
+#endif
+
+#ifndef _SECURECRT_ERRCODE_VALUES_DEFINED
+ #define _SECURECRT_ERRCODE_VALUES_DEFINED
+ #define EINVAL 22
+ #define STRUNCATE 80
+#endif
+
+#ifndef _countof
+ #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Miscellaneous global support
+
+// define useful macros from winuser.h
+#ifndef IS_INTRESOURCE
+ #define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)
+#endif // IS_INTRESOURCE
+
+// protect template members from windowsx.h macros
+#ifdef _INC_WINDOWSX
+ #undef SubclassWindow
+#endif // _INC_WINDOWSX
+
+// define useful macros from windowsx.h
+#ifndef GET_X_LPARAM
+ #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam))
+#endif
+#ifndef GET_Y_LPARAM
+ #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam))
+#endif
+
+// Dummy structs for compiling with /CLR
+#if (_MSC_VER >= 1300) && defined(_MANAGED)
+ __if_not_exists(_IMAGELIST::_IMAGELIST) { struct _IMAGELIST { }; }
+ __if_not_exists(_TREEITEM::_TREEITEM) { struct _TREEITEM { }; }
+ __if_not_exists(_PSP::_PSP) { struct _PSP { }; }
+#endif
+
+// Define ATLVERIFY macro for ATL3
+#if (_ATL_VER < 0x0700)
+ #ifndef ATLVERIFY
+ #ifdef _DEBUG
+ #define ATLVERIFY(expr) ATLASSERT(expr)
+ #else
+ #define ATLVERIFY(expr) (expr)
+ #endif // DEBUG
+ #endif // ATLVERIFY
+#endif // (_ATL_VER < 0x0700)
+
+// Forward declaration for ATL3 fix
+#if (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE)
+ namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); };
+#endif
+
+
+namespace WTL
+{
+
+#if (_ATL_VER >= 0x0700)
+ DECLARE_TRACE_CATEGORY(atlTraceUI);
+ #ifdef _DEBUG
+ __declspec(selectany) ATL::CTraceCategory atlTraceUI(_T("atlTraceUI"));
+ #endif // _DEBUG
+#else // !(_ATL_VER >= 0x0700)
+ enum wtlTraceFlags
+ {
+ atlTraceUI = 0x10000000
+ };
+#endif // !(_ATL_VER >= 0x0700)
+
+// Windows version helper
+inline bool AtlIsOldWindows()
+{
+ OSVERSIONINFO ovi = { 0 };
+ ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ BOOL bRet = ::GetVersionEx(&ovi);
+ return (!bRet || !((ovi.dwMajorVersion >= 5) || (ovi.dwMajorVersion == 4 && ovi.dwMinorVersion >= 90)));
+}
+
+// Default GUI font helper - "MS Shell Dlg" stock font
+inline HFONT AtlGetDefaultGuiFont()
+{
+#ifndef _WIN32_WCE
+ return (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
+#else // CE specific
+ return (HFONT)::GetStockObject(SYSTEM_FONT);
+#endif // _WIN32_WCE
+}
+
+// Control font helper - default font for controls not in a dialog
+// (NOTE: Caller owns the font, and should destroy it when it's no longer needed)
+inline HFONT AtlCreateControlFont()
+{
+#ifndef _WIN32_WCE
+ LOGFONT lf = { 0 };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);
+ HFONT hFont = ::CreateFontIndirect(&lf);
+ ATLASSERT(hFont != NULL);
+ return hFont;
+#else // CE specific
+ return (HFONT)::GetStockObject(SYSTEM_FONT);
+#endif // _WIN32_WCE
+}
+
+// Bold font helper
+// (NOTE: Caller owns the font, and should destroy it when it's no longer needed)
+inline HFONT AtlCreateBoldFont(HFONT hFont = NULL)
+{
+ LOGFONT lf = { 0 };
+#ifndef _WIN32_WCE
+ if(hFont == NULL)
+ ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);
+ else
+ ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT));
+#else // CE specific
+ if(hFont == NULL)
+ hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
+ ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT));
+#endif // _WIN32_WCE
+ lf.lfWeight = FW_BOLD;
+ HFONT hFontBold = ::CreateFontIndirect(&lf);
+ ATLASSERT(hFontBold != NULL);
+ return hFontBold;
+}
+
+// Common Controls initialization helper
+inline BOOL AtlInitCommonControls(DWORD dwFlags)
+{
+ INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX), dwFlags };
+ BOOL bRet = ::InitCommonControlsEx(&iccx);
+ ATLASSERT(bRet);
+ return bRet;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RunTimeHelper - helper functions for Windows version and structure sizes
+
+// Not for Windows CE
+#if defined(_WIN32_WCE) && !defined(_WTL_NO_RUNTIME_STRUCT_SIZE)
+ #define _WTL_NO_RUNTIME_STRUCT_SIZE
+#endif
+
+#ifndef _WTL_NO_RUNTIME_STRUCT_SIZE
+
+#ifndef _SIZEOF_STRUCT
+ #define _SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
+#endif
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE)
+ #define REBARBANDINFO_V6_SIZE _SIZEOF_STRUCT(REBARBANDINFO, cxHeader)
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE)
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE)
+ #define LVGROUP_V5_SIZE _SIZEOF_STRUCT(LVGROUP, uAlign)
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE)
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE)
+ #define LVTILEINFO_V5_SIZE _SIZEOF_STRUCT(LVTILEINFO, puColumns)
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE)
+
+#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE)
+ #define MCHITTESTINFO_V1_SIZE _SIZEOF_STRUCT(MCHITTESTINFO, st)
+#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE)
+
+#if !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE)
+ #define NONCLIENTMETRICS_V1_SIZE _SIZEOF_STRUCT(NONCLIENTMETRICS, lfMessageFont)
+#endif // !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE)
+
+#endif // !_WTL_NO_RUNTIME_STRUCT_SIZE
+
+namespace RunTimeHelper
+{
+#ifndef _WIN32_WCE
+ inline bool IsCommCtrl6()
+ {
+ DWORD dwMajor = 0, dwMinor = 0;
+ HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
+ return (SUCCEEDED(hRet) && (dwMajor >= 6));
+ }
+
+ inline bool IsVista()
+ {
+ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
+ BOOL bRet = ::GetVersionEx(&ovi);
+ return ((bRet != FALSE) && (ovi.dwMajorVersion >= 6));
+ }
+
+ inline bool IsThemeAvailable()
+ {
+ bool bRet = false;
+
+ if(IsCommCtrl6())
+ {
+ HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
+ if(hThemeDLL != NULL)
+ {
+ typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)();
+ PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive");
+ ATLASSERT(pfnIsThemeActive != NULL);
+ bRet = (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE);
+ if(bRet)
+ {
+ typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)();
+ PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed");
+ ATLASSERT(pfnIsAppThemed != NULL);
+ bRet = (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE);
+ }
+
+ ::FreeLibrary(hThemeDLL);
+ }
+ }
+
+ return bRet;
+ }
+
+ inline bool IsWin7()
+ {
+ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
+ BOOL bRet = ::GetVersionEx(&ovi);
+ return ((bRet != FALSE) && (ovi.dwMajorVersion == 6) && (ovi.dwMinorVersion >= 1));
+ }
+
+ inline bool IsRibbonUIAvailable()
+ {
+ static INT iRibbonUI = -1;
+
+#if defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)
+ if (iRibbonUI == -1)
+ {
+ HMODULE hRibbonDLL = ::LoadLibrary(_T("propsys.dll"));
+ if (hRibbonDLL != NULL)
+ {
+ const GUID CLSID_UIRibbonFramework = { 0x926749fa, 0x2615, 0x4987, { 0x88, 0x45, 0xc3, 0x3e, 0x65, 0xf2, 0xb9, 0x57 } };
+ // block - create instance
+ {
+ ATL::CComPtr<IUnknown> pIUIFramework;
+ iRibbonUI = SUCCEEDED(pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework)) ? 1 : 0;
+ }
+ ::FreeLibrary(hRibbonDLL);
+ }
+ else
+ {
+ iRibbonUI = 0;
+ }
+ }
+#endif // defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)
+
+ return (iRibbonUI == 1);
+ }
+
+#endif // !_WIN32_WCE
+
+ inline int SizeOf_REBARBANDINFO()
+ {
+ int nSize = sizeof(REBARBANDINFO);
+#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ if(!(IsVista() && IsCommCtrl6()))
+ nSize = REBARBANDINFO_V6_SIZE;
+#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ return nSize;
+ }
+
+#if (_WIN32_WINNT >= 0x501)
+ inline int SizeOf_LVGROUP()
+ {
+ int nSize = sizeof(LVGROUP);
+#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ if(!IsVista())
+ nSize = LVGROUP_V5_SIZE;
+#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ return nSize;
+ }
+
+ inline int SizeOf_LVTILEINFO()
+ {
+ int nSize = sizeof(LVTILEINFO);
+#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ if(!IsVista())
+ nSize = LVTILEINFO_V5_SIZE;
+#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)
+ return nSize;
+ }
+#endif // (_WIN32_WINNT >= 0x501)
+
+ inline int SizeOf_MCHITTESTINFO()
+ {
+ int nSize = sizeof(MCHITTESTINFO);
+#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ if(!(IsVista() && IsCommCtrl6()))
+ nSize = MCHITTESTINFO_V1_SIZE;
+#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ return nSize;
+ }
+
+#ifndef _WIN32_WCE
+ inline int SizeOf_NONCLIENTMETRICS()
+ {
+ int nSize = sizeof(NONCLIENTMETRICS);
+#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)
+ if(!IsVista())
+ nSize = NONCLIENTMETRICS_V1_SIZE;
+#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)
+ return nSize;
+ }
+#endif // !_WIN32_WCE
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ModuleHelper - helper functions for ATL3 and ATL7 module classes
+
+namespace ModuleHelper
+{
+ inline HINSTANCE GetModuleInstance()
+ {
+#if (_ATL_VER >= 0x0700)
+ return ATL::_AtlBaseModule.GetModuleInstance();
+#else // !(_ATL_VER >= 0x0700)
+ return ATL::_pModule->GetModuleInstance();
+#endif // !(_ATL_VER >= 0x0700)
+ }
+
+ inline HINSTANCE GetResourceInstance()
+ {
+#if (_ATL_VER >= 0x0700)
+ return ATL::_AtlBaseModule.GetResourceInstance();
+#else // !(_ATL_VER >= 0x0700)
+ return ATL::_pModule->GetResourceInstance();
+#endif // !(_ATL_VER >= 0x0700)
+ }
+
+ inline void AddCreateWndData(ATL::_AtlCreateWndData* pData, void* pObject)
+ {
+#if (_ATL_VER >= 0x0700)
+ ATL::_AtlWinModule.AddCreateWndData(pData, pObject);
+#else // !(_ATL_VER >= 0x0700)
+ ATL::_pModule->AddCreateWndData(pData, pObject);
+#endif // !(_ATL_VER >= 0x0700)
+ }
+
+ inline void* ExtractCreateWndData()
+ {
+#if (_ATL_VER >= 0x0700)
+ return ATL::_AtlWinModule.ExtractCreateWndData();
+#else // !(_ATL_VER >= 0x0700)
+ return ATL::_pModule->ExtractCreateWndData();
+#endif // !(_ATL_VER >= 0x0700)
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SecureHelper - helper functions for VS2005 secure CRT
+
+namespace SecureHelper
+{
+ inline void strcpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::strcpy_s(lpstrDest, cchDest, lpstrSrc);
+#else
+ if(cchDest > (size_t)lstrlenA(lpstrSrc))
+ ATLVERIFY(lstrcpyA(lpstrDest, lpstrSrc) != NULL);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline void strcpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::wcscpy_s(lpstrDest, cchDest, lpstrSrc);
+#else
+ if(cchDest > (size_t)lstrlenW(lpstrSrc))
+ ATLVERIFY(lstrcpyW(lpstrDest, lpstrSrc) != NULL);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline void strcpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc)
+ {
+#ifdef _UNICODE
+ strcpyW_x(lpstrDest, cchDest, lpstrSrc);
+#else
+ strcpyA_x(lpstrDest, cchDest, lpstrSrc);
+#endif
+ }
+
+ inline errno_t strncpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc, size_t cchCount)
+ {
+#if _SECURE_ATL
+ return ATL::Checked::strncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount);
+#else
+ errno_t nRet = 0;
+ if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL)
+ {
+ nRet = EINVAL;
+ }
+ else if(cchCount == _TRUNCATE)
+ {
+ cchCount = min(cchDest - 1, size_t(lstrlenA(lpstrSrc)));
+ nRet = STRUNCATE;
+ }
+ else if(cchDest <= cchCount)
+ {
+ lpstrDest[0] = 0;
+ nRet = EINVAL;
+ }
+ if(nRet == 0 || nRet == STRUNCATE)
+ nRet = (lstrcpynA(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL;
+ ATLASSERT(nRet == 0 || nRet == STRUNCATE);
+ return nRet;
+#endif
+ }
+
+ inline errno_t strncpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc, size_t cchCount)
+ {
+#if _SECURE_ATL
+ return ATL::Checked::wcsncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount);
+#else
+ errno_t nRet = 0;
+ if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL)
+ {
+ nRet = EINVAL;
+ }
+ else if(cchCount == _TRUNCATE)
+ {
+ cchCount = min(cchDest - 1, size_t(lstrlenW(lpstrSrc)));
+ nRet = STRUNCATE;
+ }
+ else if(cchDest <= cchCount)
+ {
+ lpstrDest[0] = 0;
+ nRet = EINVAL;
+ }
+ if(nRet == 0 || nRet == STRUNCATE)
+ nRet = (lstrcpynW(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL;
+ ATLASSERT(nRet == 0 || nRet == STRUNCATE);
+ return nRet;
+#endif
+ }
+
+ inline errno_t strncpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc, size_t cchCount)
+ {
+#ifdef _UNICODE
+ return strncpyW_x(lpstrDest, cchDest, lpstrSrc, cchCount);
+#else
+ return strncpyA_x(lpstrDest, cchDest, lpstrSrc, cchCount);
+#endif
+ }
+
+ inline void strcatA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::strcat_s(lpstrDest, cchDest, lpstrSrc);
+#else
+ if(cchDest > (size_t)lstrlenA(lpstrSrc))
+ ATLVERIFY(lstrcatA(lpstrDest, lpstrSrc) != NULL);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline void strcatW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::wcscat_s(lpstrDest, cchDest, lpstrSrc);
+#else
+ if(cchDest > (size_t)lstrlenW(lpstrSrc))
+ ATLVERIFY(lstrcatW(lpstrDest, lpstrSrc) != NULL);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline void strcat_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc)
+ {
+#ifdef _UNICODE
+ strcatW_x(lpstrDest, cchDest, lpstrSrc);
+#else
+ strcatA_x(lpstrDest, cchDest, lpstrSrc);
+#endif
+ }
+
+ inline void memcpy_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::memcpy_s(pDest, cbDest, pSrc, cbSrc);
+#else
+ if(cbDest >= cbSrc)
+ memcpy(pDest, pSrc, cbSrc);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline void memmove_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc)
+ {
+#if _SECURE_ATL
+ ATL::Checked::memmove_s(pDest, cbDest, pSrc, cbSrc);
+#else
+ if(cbDest >= cbSrc)
+ memmove(pDest, pSrc, cbSrc);
+ else
+ ATLASSERT(FALSE);
+#endif
+ }
+
+ inline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args)
+ {
+#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)
+ return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args);
+#else
+ cchBuff; // Avoid unused argument warning
+#pragma warning(disable: 4996)
+ return _vstprintf(lpstrBuff, lpstrFormat, args);
+#pragma warning(default: 4996)
+#endif
+ }
+
+ inline int wvsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args)
+ {
+#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)
+ return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args);
+#else
+ cchBuff; // Avoid unused argument warning
+ return ::wvsprintf(lpstrBuff, lpstrFormat, args);
+#endif
+ }
+
+ inline int sprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...)
+ {
+ va_list args;
+ va_start(args, lpstrFormat);
+ int nRes = vsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args);
+ va_end(args);
+ return nRes;
+ }
+
+ inline int wsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...)
+ {
+ va_list args;
+ va_start(args, lpstrFormat);
+ int nRes = wvsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args);
+ va_end(args);
+ return nRes;
+ }
+}; // namespace SecureHelper
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMessageFilter - Interface for message filter support
+
+class CMessageFilter
+{
+public:
+ virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CIdleHandler - Interface for idle processing
+
+class CIdleHandler
+{
+public:
+ virtual BOOL OnIdle() = 0;
+};
+
+#ifndef _ATL_NO_OLD_NAMES
+ // for compatilibility with old names only
+ typedef CIdleHandler CUpdateUIObject;
+ #define DoUpdate OnIdle
+#endif // !_ATL_NO_OLD_NAMES
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMessageLoop - message loop implementation
+
+class CMessageLoop
+{
+public:
+ ATL::CSimpleArray<CMessageFilter*> m_aMsgFilter;
+ ATL::CSimpleArray<CIdleHandler*> m_aIdleHandler;
+ MSG m_msg;
+
+// Message filter operations
+ BOOL AddMessageFilter(CMessageFilter* pMessageFilter)
+ {
+ return m_aMsgFilter.Add(pMessageFilter);
+ }
+
+ BOOL RemoveMessageFilter(CMessageFilter* pMessageFilter)
+ {
+ return m_aMsgFilter.Remove(pMessageFilter);
+ }
+
+// Idle handler operations
+ BOOL AddIdleHandler(CIdleHandler* pIdleHandler)
+ {
+ return m_aIdleHandler.Add(pIdleHandler);
+ }
+
+ BOOL RemoveIdleHandler(CIdleHandler* pIdleHandler)
+ {
+ return m_aIdleHandler.Remove(pIdleHandler);
+ }
+
+#ifndef _ATL_NO_OLD_NAMES
+ // for compatilibility with old names only
+ BOOL AddUpdateUI(CIdleHandler* pIdleHandler)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and AddUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n"));
+ return AddIdleHandler(pIdleHandler);
+ }
+
+ BOOL RemoveUpdateUI(CIdleHandler* pIdleHandler)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and RemoveUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n"));
+ return RemoveIdleHandler(pIdleHandler);
+ }
+#endif // !_ATL_NO_OLD_NAMES
+
+// message loop
+ int Run()
+ {
+ BOOL bDoIdle = TRUE;
+ int nIdleCount = 0;
+ BOOL bRet;
+
+ for(;;)
+ {
+ while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if(!OnIdle(nIdleCount++))
+ bDoIdle = FALSE;
+ }
+
+ bRet = ::GetMessage(&m_msg, NULL, 0, 0);
+
+ if(bRet == -1)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
+ continue; // error, don't process
+ }
+ else if(!bRet)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
+ break; // WM_QUIT, exit message loop
+ }
+
+ if(!PreTranslateMessage(&m_msg))
+ {
+ ::TranslateMessage(&m_msg);
+ ::DispatchMessage(&m_msg);
+ }
+
+ if(IsIdleMessage(&m_msg))
+ {
+ bDoIdle = TRUE;
+ nIdleCount = 0;
+ }
+ }
+
+ return (int)m_msg.wParam;
+ }
+
+ static BOOL IsIdleMessage(MSG* pMsg)
+ {
+ // These messages should NOT cause idle processing
+ switch(pMsg->message)
+ {
+ case WM_MOUSEMOVE:
+#ifndef _WIN32_WCE
+ case WM_NCMOUSEMOVE:
+#endif // !_WIN32_WCE
+ case WM_PAINT:
+ case 0x0118: // WM_SYSTIMER (caret blink)
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+// Overrideables
+ // Override to change message filtering
+ virtual BOOL PreTranslateMessage(MSG* pMsg)
+ {
+ // loop backwards
+ for(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--)
+ {
+ CMessageFilter* pMessageFilter = m_aMsgFilter[i];
+ if(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg))
+ return TRUE;
+ }
+ return FALSE; // not translated
+ }
+
+ // override to change idle processing
+ virtual BOOL OnIdle(int /*nIdleCount*/)
+ {
+ for(int i = 0; i < m_aIdleHandler.GetSize(); i++)
+ {
+ CIdleHandler* pIdleHandler = m_aIdleHandler[i];
+ if(pIdleHandler != NULL)
+ pIdleHandler->OnIdle();
+ }
+ return FALSE; // don't continue
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CStaticDataInitCriticalSectionLock and CWindowCreateCriticalSectionLock
+// internal classes to manage critical sections for both ATL3 and ATL7
+
+class CStaticDataInitCriticalSectionLock
+{
+public:
+#if (_ATL_VER >= 0x0700)
+ ATL::CComCritSecLock<ATL::CComCriticalSection> m_cslock;
+
+ CStaticDataInitCriticalSectionLock() : m_cslock(ATL::_pAtlModule->m_csStaticDataInitAndTypeInfo, false)
+ { }
+#endif // (_ATL_VER >= 0x0700)
+
+ HRESULT Lock()
+ {
+#if (_ATL_VER >= 0x0700)
+ return m_cslock.Lock();
+#else // !(_ATL_VER >= 0x0700)
+ ::EnterCriticalSection(&ATL::_pModule->m_csStaticDataInit);
+ return S_OK;
+#endif // !(_ATL_VER >= 0x0700)
+ }
+
+ void Unlock()
+ {
+#if (_ATL_VER >= 0x0700)
+ m_cslock.Unlock();
+#else // !(_ATL_VER >= 0x0700)
+ ::LeaveCriticalSection(&ATL::_pModule->m_csStaticDataInit);
+#endif // !(_ATL_VER >= 0x0700)
+ }
+};
+
+
+class CWindowCreateCriticalSectionLock
+{
+public:
+#if (_ATL_VER >= 0x0700)
+ ATL::CComCritSecLock<ATL::CComCriticalSection> m_cslock;
+
+ CWindowCreateCriticalSectionLock() : m_cslock(ATL::_AtlWinModule.m_csWindowCreate, false)
+ { }
+#endif // (_ATL_VER >= 0x0700)
+
+ HRESULT Lock()
+ {
+#if (_ATL_VER >= 0x0700)
+ return m_cslock.Lock();
+#else // !(_ATL_VER >= 0x0700)
+ ::EnterCriticalSection(&ATL::_pModule->m_csWindowCreate);
+ return S_OK;
+#endif // !(_ATL_VER >= 0x0700)
+ }
+
+ void Unlock()
+ {
+#if (_ATL_VER >= 0x0700)
+ m_cslock.Unlock();
+#else // !(_ATL_VER >= 0x0700)
+ ::LeaveCriticalSection(&ATL::_pModule->m_csWindowCreate);
+#endif // !(_ATL_VER >= 0x0700)
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTempBuffer - helper class for stack allocations for ATL3
+
+#ifndef _WTL_STACK_ALLOC_THRESHOLD
+ #define _WTL_STACK_ALLOC_THRESHOLD 512
+#endif
+
+#if (_ATL_VER >= 0x0700)
+
+using ATL::CTempBuffer;
+
+#else // !(_ATL_VER >= 0x0700)
+
+#ifndef SIZE_MAX
+ #ifdef _WIN64
+ #define SIZE_MAX _UI64_MAX
+ #else
+ #define SIZE_MAX UINT_MAX
+ #endif
+#endif
+
+#pragma warning(disable: 4284) // warning for operator ->
+
+template<typename T, int t_nFixedBytes = 128>
+class CTempBuffer
+{
+public:
+ CTempBuffer() : m_p(NULL)
+ {
+ }
+
+ CTempBuffer(size_t nElements) : m_p(NULL)
+ {
+ Allocate(nElements);
+ }
+
+ ~CTempBuffer()
+ {
+ if(m_p != reinterpret_cast<T*>(m_abFixedBuffer))
+ free(m_p);
+ }
+
+ operator T*() const
+ {
+ return m_p;
+ }
+
+ T* operator ->() const
+ {
+ ATLASSERT(m_p != NULL);
+ return m_p;
+ }
+
+ T* Allocate(size_t nElements)
+ {
+ ATLASSERT(nElements <= (SIZE_MAX / sizeof(T)));
+ return AllocateBytes(nElements * sizeof(T));
+ }
+
+ T* AllocateBytes(size_t nBytes)
+ {
+ ATLASSERT(m_p == NULL);
+ if(nBytes > t_nFixedBytes)
+ m_p = static_cast<T*>(malloc(nBytes));
+ else
+ m_p = reinterpret_cast<T*>(m_abFixedBuffer);
+
+ return m_p;
+ }
+
+private:
+ T* m_p;
+ BYTE m_abFixedBuffer[t_nFixedBytes];
+};
+
+#pragma warning(default: 4284)
+
+#endif // !(_ATL_VER >= 0x0700)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppModule - module class for an application
+
+class CAppModule : public ATL::CComModule
+{
+public:
+ DWORD m_dwMainThreadID;
+ ATL::CSimpleMap<DWORD, CMessageLoop*>* m_pMsgLoopMap;
+ ATL::CSimpleArray<HWND>* m_pSettingChangeNotify;
+
+// Overrides of CComModule::Init and Term
+ HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL)
+ {
+ HRESULT hRet = CComModule::Init(pObjMap, hInstance, pLibID);
+ if(FAILED(hRet))
+ return hRet;
+
+ m_dwMainThreadID = ::GetCurrentThreadId();
+ typedef ATL::CSimpleMap<DWORD, CMessageLoop*> _mapClass;
+ m_pMsgLoopMap = NULL;
+ ATLTRY(m_pMsgLoopMap = new _mapClass);
+ if(m_pMsgLoopMap == NULL)
+ return E_OUTOFMEMORY;
+ m_pSettingChangeNotify = NULL;
+
+ return hRet;
+ }
+
+ void Term()
+ {
+ TermSettingChangeNotify();
+ delete m_pMsgLoopMap;
+ CComModule::Term();
+ }
+
+// Message loop map methods
+ BOOL AddMessageLoop(CMessageLoop* pMsgLoop)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ ATLASSERT(pMsgLoop != NULL);
+ ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL); // not in map yet
+
+ BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop);
+
+ lock.Unlock();
+
+ return bRet;
+ }
+
+ BOOL RemoveMessageLoop()
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId());
+
+ lock.Unlock();
+
+ return bRet;
+ }
+
+ CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\n"));
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+
+ CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID);
+
+ lock.Unlock();
+
+ return pLoop;
+ }
+
+// Setting change notify methods
+ // Note: Call this from the main thread for MSDI apps
+ BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ if(m_pSettingChangeNotify == NULL)
+ {
+ typedef ATL::CSimpleArray<HWND> _notifyClass;
+ ATLTRY(m_pSettingChangeNotify = new _notifyClass);
+ ATLASSERT(m_pSettingChangeNotify != NULL);
+ }
+
+ BOOL bRet = (m_pSettingChangeNotify != NULL);
+ if(bRet && m_pSettingChangeNotify->GetSize() == 0)
+ {
+ // init everything
+ _ATL_EMPTY_DLGTEMPLATE templ;
+ HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);
+ ATLASSERT(::IsWindow(hNtfWnd));
+ if(::IsWindow(hNtfWnd))
+ {
+// need conditional code because types don't match in winuser.h
+#ifdef _WIN64
+ ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);
+#else
+ ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));
+#endif
+ bRet = m_pSettingChangeNotify->Add(hNtfWnd);
+ }
+ else
+ {
+ bRet = FALSE;
+ }
+ }
+
+ lock.Unlock();
+
+ return bRet;
+ }
+
+ void TermSettingChangeNotify()
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\n"));
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0)
+ ::DestroyWindow((*m_pSettingChangeNotify)[0]);
+ delete m_pSettingChangeNotify;
+ m_pSettingChangeNotify = NULL;
+
+ lock.Unlock();
+ }
+
+ BOOL AddSettingChangeNotify(HWND hWnd)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ ATLASSERT(::IsWindow(hWnd));
+ BOOL bRet = FALSE;
+ if(InitSettingChangeNotify() != FALSE)
+ bRet = m_pSettingChangeNotify->Add(hWnd);
+
+ lock.Unlock();
+
+ return bRet;
+ }
+
+ BOOL RemoveSettingChangeNotify(HWND hWnd)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ BOOL bRet = FALSE;
+ if(m_pSettingChangeNotify != NULL)
+ bRet = m_pSettingChangeNotify->Remove(hWnd);
+
+ lock.Unlock();
+
+ return bRet;
+ }
+
+// Implementation - setting change notify dialog template and dialog procedure
+ struct _ATL_EMPTY_DLGTEMPLATE : DLGTEMPLATE
+ {
+ _ATL_EMPTY_DLGTEMPLATE()
+ {
+ memset(this, 0, sizeof(_ATL_EMPTY_DLGTEMPLATE));
+ style = WS_POPUP;
+ }
+ WORD wMenu, wClass, wTitle;
+ };
+
+#ifdef _WIN64
+ static INT_PTR CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+#else
+ static BOOL CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+#endif
+ {
+ if(uMsg == WM_SETTINGCHANGE)
+ {
+// need conditional code because types don't match in winuser.h
+#ifdef _WIN64
+ CAppModule* pModule = (CAppModule*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
+#else
+ CAppModule* pModule = (CAppModule*)LongToPtr(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
+#endif
+ ATLASSERT(pModule != NULL);
+ ATLASSERT(pModule->m_pSettingChangeNotify != NULL);
+ const UINT uTimeout = 1500; // ms
+ for(int i = 1; i < pModule->m_pSettingChangeNotify->GetSize(); i++)
+ {
+#if !defined(_WIN32_WCE)
+ ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_ABORTIFHUNG, uTimeout, NULL);
+#elif(_WIN32_WCE >= 400) // CE specific
+ ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_NORMAL, uTimeout, NULL);
+#else // _WIN32_WCE < 400 specific
+ uTimeout;
+ ::SendMessage((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam);
+#endif
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CServerAppModule - module class for a COM server application
+
+class CServerAppModule : public CAppModule
+{
+public:
+ HANDLE m_hEventShutdown;
+ bool m_bActivity;
+ DWORD m_dwTimeOut;
+ DWORD m_dwPause;
+
+// Override of CAppModule::Init
+ HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL)
+ {
+ m_dwTimeOut = 5000;
+ m_dwPause = 1000;
+ return CAppModule::Init(pObjMap, hInstance, pLibID);
+ }
+
+ void Term()
+ {
+ if(m_hEventShutdown != NULL && ::CloseHandle(m_hEventShutdown))
+ m_hEventShutdown = NULL;
+ CAppModule::Term();
+ }
+
+// COM Server methods
+ LONG Unlock()
+ {
+ LONG lRet = CComModule::Unlock();
+ if(lRet == 0)
+ {
+ m_bActivity = true;
+ ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero
+ }
+ return lRet;
+ }
+
+ void MonitorShutdown()
+ {
+ for(;;)
+ {
+ ::WaitForSingleObject(m_hEventShutdown, INFINITE);
+ DWORD dwWait = 0;
+ do
+ {
+ m_bActivity = false;
+ dwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut);
+ }
+ while(dwWait == WAIT_OBJECT_0);
+ // timed out
+ if(!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail
+ {
+#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) && defined(_ATL_FREE_THREADED) && !defined(_WIN32_WCE)
+ ::CoSuspendClassObjects();
+ if(!m_bActivity && m_nLockCnt == 0)
+#endif
+ break;
+ }
+ }
+ // This handle should be valid now. If it isn't,
+ // check if _Module.Term was called first (it shouldn't)
+ if(::CloseHandle(m_hEventShutdown))
+ m_hEventShutdown = NULL;
+ ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0);
+ }
+
+ bool StartMonitor()
+ {
+ m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL);
+ if(m_hEventShutdown == NULL)
+ return false;
+ DWORD dwThreadID = 0;
+#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE)
+ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))MonitorProc, this, 0, (UINT*)&dwThreadID);
+#else
+ HANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
+#endif
+ bool bRet = (hThread != NULL);
+ if(bRet)
+ ::CloseHandle(hThread);
+ return bRet;
+ }
+
+ static DWORD WINAPI MonitorProc(void* pv)
+ {
+ CServerAppModule* p = (CServerAppModule*)pv;
+ p->MonitorShutdown();
+ return 0;
+ }
+
+#if (_ATL_VER < 0x0700)
+ // search for an occurence of string p2 in string p1
+ static LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
+ {
+ while(p1 != NULL && *p1 != NULL)
+ {
+ LPCTSTR p = p2;
+ while(p != NULL && *p != NULL)
+ {
+ if(*p1 == *p)
+ return ::CharNext(p1);
+ p = ::CharNext(p);
+ }
+ p1 = ::CharNext(p1);
+ }
+ return NULL;
+ }
+#endif // (_ATL_VER < 0x0700)
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRegKeyEx - adds type-specific methods to ATL3 CRegKey
+
+#if (_ATL_VER < 0x0700)
+
+class CRegKeyEx : public ATL::CRegKey
+{
+public:
+// Constructors and operators
+ CRegKeyEx(HKEY hKey = NULL)
+ {
+ m_hKey = hKey;
+ }
+
+ CRegKeyEx(CRegKeyEx& key)
+ {
+ Attach(key.Detach());
+ }
+
+ CRegKeyEx& operator =(CRegKeyEx& key)
+ {
+ Close();
+ Attach(key.Detach());
+ return *this;
+ }
+
+// Methods
+ LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes)
+ {
+ ATLASSERT(m_hKey != NULL);
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast<const BYTE*>(pValue), nBytes);
+ }
+
+ LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+
+ OLECHAR szGUID[64] = { 0 };
+ ::StringFromGUID2(guidValue, szGUID, 64);
+
+ USES_CONVERSION;
+ LPCTSTR lpstr = OLE2CT(szGUID);
+#ifndef _UNICODE
+ if(lpstr == NULL)
+ return E_OUTOFMEMORY;
+#endif
+ return SetStringValue(pszValueName, lpstr);
+ }
+
+ LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes)
+ {
+ ATLASSERT(m_hKey != NULL);
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast<const BYTE*>(pValue), nBytes);
+ }
+
+ LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast<const BYTE*>(&dwValue), sizeof(DWORD));
+ }
+
+#ifndef _WIN32_WCE
+ LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast<const BYTE*>(&qwValue), sizeof(ULONGLONG));
+ }
+#endif
+
+ LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ)
+ {
+ ATLASSERT(m_hKey != NULL);
+ if(pszValue == NULL)
+ {
+ ATLASSERT(FALSE);
+ return ERROR_INVALID_DATA;
+ }
+ ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ));
+
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast<const BYTE*>(pszValue), (lstrlen(pszValue) + 1) * sizeof(TCHAR));
+ }
+
+ LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+ if(pszValue == NULL)
+ {
+ ATLASSERT(FALSE);
+ return ERROR_INVALID_DATA;
+ }
+
+ ULONG nBytes = 0;
+ ULONG nLength = 0;
+ LPCTSTR pszTemp = pszValue;
+ do
+ {
+ nLength = lstrlen(pszTemp) + 1;
+ pszTemp += nLength;
+ nBytes += nLength * sizeof(TCHAR);
+ } while (nLength != 1);
+
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast<const BYTE*>(pszValue), nBytes);
+ }
+
+ LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes)
+ {
+ ATLASSERT(m_hKey != NULL);
+ return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast<LPBYTE>(pData), pnBytes);
+ }
+
+ LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+
+ guidValue = GUID_NULL;
+
+ TCHAR szGUID[64] = { 0 };
+ ULONG nCount = 64;
+ LONG lRes = QueryStringValue(pszValueName, szGUID, &nCount);
+
+ if (lRes != ERROR_SUCCESS)
+ return lRes;
+
+ if(szGUID[0] != _T('{'))
+ return ERROR_INVALID_DATA;
+
+ USES_CONVERSION;
+ LPOLESTR lpstr = T2OLE(szGUID);
+#ifndef _UNICODE
+ if(lpstr == NULL)
+ return E_OUTOFMEMORY;
+#endif
+
+ HRESULT hr = ::CLSIDFromString(lpstr, &guidValue);
+ if (FAILED(hr))
+ return ERROR_INVALID_DATA;
+
+ return ERROR_SUCCESS;
+ }
+
+ LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes)
+ {
+ ATLASSERT(pnBytes != NULL);
+ ATLASSERT(m_hKey != NULL);
+
+ DWORD dwType = 0;
+ LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pValue), pnBytes);
+ if (lRes != ERROR_SUCCESS)
+ return lRes;
+ if (dwType != REG_BINARY)
+ return ERROR_INVALID_DATA;
+
+ return ERROR_SUCCESS;
+ }
+
+ LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+
+ ULONG nBytes = sizeof(DWORD);
+ DWORD dwType = 0;
+ LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(&dwValue), &nBytes);
+ if (lRes != ERROR_SUCCESS)
+ return lRes;
+ if (dwType != REG_DWORD)
+ return ERROR_INVALID_DATA;
+
+ return ERROR_SUCCESS;
+ }
+
+ LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue)
+ {
+ ATLASSERT(m_hKey != NULL);
+
+ ULONG nBytes = sizeof(ULONGLONG);
+ DWORD dwType = 0;
+ LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(&qwValue), &nBytes);
+ if (lRes != ERROR_SUCCESS)
+ return lRes;
+ if (dwType != REG_QWORD)
+ return ERROR_INVALID_DATA;
+
+ return ERROR_SUCCESS;
+ }
+
+ LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars)
+ {
+ ATLASSERT(m_hKey != NULL);
+ ATLASSERT(pnChars != NULL);
+
+ ULONG nBytes = (*pnChars) * sizeof(TCHAR);
+ DWORD dwType = 0;
+ *pnChars = 0;
+ LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pszValue), &nBytes);
+
+ if (lRes != ERROR_SUCCESS)
+ {
+ return lRes;
+ }
+
+ if(dwType != REG_SZ && dwType != REG_EXPAND_SZ)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (pszValue != NULL)
+ {
+ if(nBytes != 0)
+ {
+ if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0))
+ return ERROR_INVALID_DATA;
+ }
+ else
+ {
+ pszValue[0] = _T('\0');
+ }
+ }
+
+ *pnChars = nBytes / sizeof(TCHAR);
+
+ return ERROR_SUCCESS;
+ }
+
+ LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars)
+ {
+ ATLASSERT(m_hKey != NULL);
+ ATLASSERT(pnChars != NULL);
+
+ if (pszValue != NULL && *pnChars < 2)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ ULONG nBytes = (*pnChars) * sizeof(TCHAR);
+ DWORD dwType = 0;
+ *pnChars = 0;
+ LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pszValue), &nBytes);
+ if (lRes != ERROR_SUCCESS)
+ return lRes;
+ if (dwType != REG_MULTI_SZ)
+ return ERROR_INVALID_DATA;
+ if (pszValue != NULL && (nBytes % sizeof(TCHAR) != 0 || nBytes / sizeof(TCHAR) < 1 || pszValue[nBytes / sizeof(TCHAR) - 1] != 0 || ((nBytes / sizeof(TCHAR)) > 1 && pszValue[nBytes / sizeof(TCHAR) - 2] != 0)))
+ return ERROR_INVALID_DATA;
+
+ *pnChars = nBytes / sizeof(TCHAR);
+
+ return ERROR_SUCCESS;
+ }
+};
+
+#else // !(_ATL_VER < 0x0700)
+
+typedef ATL::CRegKey CRegKeyEx;
+
+#endif // !(_ATL_VER < 0x0700)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CString forward reference (enables CString use in atluser.h and atlgdi.h)
+
+#if defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING)
+ #define _WTL_USE_CSTRING
+#endif // defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING)
+
+#ifdef _WTL_USE_CSTRING
+ class CString; // forward declaration (include atlmisc.h for the whole class)
+#endif // _WTL_USE_CSTRING
+
+// CString namespace
+#ifndef _CSTRING_NS
+ #ifdef __ATLSTR_H__
+ #define _CSTRING_NS ATL
+ #else
+ #define _CSTRING_NS WTL
+ #endif
+#endif // _CSTRING_NS
+
+// Type classes namespace
+#ifndef _WTYPES_NS
+ #ifdef __ATLTYPES_H__
+ #define _WTYPES_NS
+ #else
+ #define _WTYPES_NS WTL
+ #endif
+#endif // _WTYPES_NS
+
+}; // namespace WTL
+
+
+///////////////////////////////////////////////////////////////////////////////
+// General DLL version helpers (excluded from atlbase.h if _ATL_DLL is defined)
+
+#if (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE)
+
+namespace ATL
+{
+
+inline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo)
+{
+ ATLASSERT(pDllVersionInfo != NULL);
+ if(pDllVersionInfo == NULL)
+ return E_INVALIDARG;
+
+ // We must get this function explicitly because some DLLs don't implement it.
+ DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, "DllGetVersion");
+ if(pfnDllGetVersion == NULL)
+ return E_NOTIMPL;
+
+ return (*pfnDllGetVersion)(pDllVersionInfo);
+}
+
+inline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo)
+{
+ HINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName);
+ if(hInstDLL == NULL)
+ return E_FAIL;
+ HRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo);
+ ::FreeLibrary(hInstDLL);
+ return hRet;
+}
+
+// Common Control Versions:
+// Win95/WinNT 4.0 maj=4 min=00
+// IE 3.x maj=4 min=70
+// IE 4.0 maj=4 min=71
+inline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)
+{
+ ATLASSERT(pdwMajor != NULL && pdwMinor != NULL);
+ if(pdwMajor == NULL || pdwMinor == NULL)
+ return E_INVALIDARG;
+
+ DLLVERSIONINFO dvi;
+ ::ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ HRESULT hRet = AtlGetDllVersion(_T("comctl32.dll"), &dvi);
+
+ if(SUCCEEDED(hRet))
+ {
+ *pdwMajor = dvi.dwMajorVersion;
+ *pdwMinor = dvi.dwMinorVersion;
+ }
+ else if(hRet == E_NOTIMPL)
+ {
+ // If DllGetVersion is not there, then the DLL is a version
+ // previous to the one shipped with IE 3.x
+ *pdwMajor = 4;
+ *pdwMinor = 0;
+ hRet = S_OK;
+ }
+
+ return hRet;
+}
+
+// Shell Versions:
+// Win95/WinNT 4.0 maj=4 min=00
+// IE 3.x, IE 4.0 without Web Integrated Desktop maj=4 min=00
+// IE 4.0 with Web Integrated Desktop maj=4 min=71
+// IE 4.01 with Web Integrated Desktop maj=4 min=72
+inline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)
+{
+ ATLASSERT(pdwMajor != NULL && pdwMinor != NULL);
+ if(pdwMajor == NULL || pdwMinor == NULL)
+ return E_INVALIDARG;
+
+ DLLVERSIONINFO dvi;
+ ::ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ HRESULT hRet = AtlGetDllVersion(_T("shell32.dll"), &dvi);
+
+ if(SUCCEEDED(hRet))
+ {
+ *pdwMajor = dvi.dwMajorVersion;
+ *pdwMinor = dvi.dwMinorVersion;
+ }
+ else if(hRet == E_NOTIMPL)
+ {
+ // If DllGetVersion is not there, then the DLL is a version
+ // previous to the one shipped with IE 4.x
+ *pdwMajor = 4;
+ *pdwMinor = 0;
+ hRet = S_OK;
+ }
+
+ return hRet;
+}
+
+}; // namespace ATL
+
+#endif // (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE)
+
+
+// These are always included
+#include "atlwinx.h"
+#include "atluser.h"
+#include "atlgdi.h"
+
+#ifndef _WTL_NO_AUTOMATIC_NAMESPACE
+using namespace WTL;
+#endif // !_WTL_NO_AUTOMATIC_NAMESPACE
+
+#endif // __ATLAPP_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLCRACK_H__
+#define __ATLCRACK_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlcrack.h requires atlapp.h to be included first
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Message map macro for cracked handlers
+
+// Note about message maps with cracked handlers:
+// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX.
+// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes,
+// but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl.
+
+#define BEGIN_MSG_MAP_EX(theClass) \
+public: \
+ BOOL m_bMsgHandled; \
+ /* "handled" management for cracked handlers */ \
+ BOOL IsMsgHandled() const \
+ { \
+ return m_bMsgHandled; \
+ } \
+ void SetMsgHandled(BOOL bHandled) \
+ { \
+ m_bMsgHandled = bHandled; \
+ } \
+ BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
+ { \
+ BOOL bOldMsgHandled = m_bMsgHandled; \
+ BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
+ m_bMsgHandled = bOldMsgHandled; \
+ return bRet; \
+ } \
+ BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \
+ { \
+ BOOL bHandled = TRUE; \
+ hWnd; \
+ uMsg; \
+ wParam; \
+ lParam; \
+ lResult; \
+ bHandled; \
+ switch(dwMsgMapID) \
+ { \
+ case 0:
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard Windows message macros
+
+// int OnCreate(LPCREATESTRUCT lpCreateStruct)
+#define MSG_WM_CREATE(func) \
+ if (uMsg == WM_CREATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
+#define MSG_WM_INITDIALOG(func) \
+ if (uMsg == WM_INITDIALOG) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct)
+#define MSG_WM_COPYDATA(func) \
+ if (uMsg == WM_COPYDATA) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroy()
+#define MSG_WM_DESTROY(func) \
+ if (uMsg == WM_DESTROY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMove(CPoint ptPos)
+#define MSG_WM_MOVE(func) \
+ if (uMsg == WM_MOVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSize(UINT nType, CSize size)
+#define MSG_WM_SIZE(func) \
+ if (uMsg == WM_SIZE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther)
+#define MSG_WM_ACTIVATE(func) \
+ if (uMsg == WM_ACTIVATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFocus(CWindow wndOld)
+#define MSG_WM_SETFOCUS(func) \
+ if (uMsg == WM_SETFOCUS) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKillFocus(CWindow wndFocus)
+#define MSG_WM_KILLFOCUS(func) \
+ if (uMsg == WM_KILLFOCUS) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnable(BOOL bEnable)
+#define MSG_WM_ENABLE(func) \
+ if (uMsg == WM_ENABLE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaint(CDCHandle dc)
+#define MSG_WM_PAINT(func) \
+ if (uMsg == WM_PAINT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnClose()
+#define MSG_WM_CLOSE(func) \
+ if (uMsg == WM_CLOSE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff)
+#define MSG_WM_QUERYENDSESSION(func) \
+ if (uMsg == WM_QUERYENDSESSION) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryOpen()
+#define MSG_WM_QUERYOPEN(func) \
+ if (uMsg == WM_QUERYOPEN) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnEraseBkgnd(CDCHandle dc)
+#define MSG_WM_ERASEBKGND(func) \
+ if (uMsg == WM_ERASEBKGND) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysColorChange()
+#define MSG_WM_SYSCOLORCHANGE(func) \
+ if (uMsg == WM_SYSCOLORCHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEndSession(BOOL bEnding, UINT uLogOff)
+#define MSG_WM_ENDSESSION(func) \
+ if (uMsg == WM_ENDSESSION) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnShowWindow(BOOL bShow, UINT nStatus)
+#define MSG_WM_SHOWWINDOW(func) \
+ if (uMsg == WM_SHOWWINDOW) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (int)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit)
+#define MSG_WM_CTLCOLOREDIT(func) \
+ if (uMsg == WM_CTLCOLOREDIT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define MSG_WM_CTLCOLORLISTBOX(func) \
+ if (uMsg == WM_CTLCOLORLISTBOX) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button)
+#define MSG_WM_CTLCOLORBTN(func) \
+ if (uMsg == WM_CTLCOLORBTN) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define MSG_WM_CTLCOLORDLG(func) \
+ if (uMsg == WM_CTLCOLORDLG) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define MSG_WM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == WM_CTLCOLORSCROLLBAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define MSG_WM_CTLCOLORSTATIC(func) \
+ if (uMsg == WM_CTLCOLORSTATIC) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
+#define MSG_WM_SETTINGCHANGE(func) \
+ if (uMsg == WM_SETTINGCHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPCTSTR)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDevModeChange(LPCTSTR lpDeviceName)
+#define MSG_WM_DEVMODECHANGE(func) \
+ if (uMsg == WM_DEVMODECHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((LPCTSTR)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivateApp(BOOL bActive, DWORD dwThreadID)
+#define MSG_WM_ACTIVATEAPP(func) \
+ if (uMsg == WM_ACTIVATEAPP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnFontChange()
+#define MSG_WM_FONTCHANGE(func) \
+ if (uMsg == WM_FONTCHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimeChange()
+#define MSG_WM_TIMECHANGE(func) \
+ if (uMsg == WM_TIMECHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCancelMode()
+#define MSG_WM_CANCELMODE(func) \
+ if (uMsg == WM_CANCELMODE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message)
+#define MSG_WM_SETCURSOR(func) \
+ if (uMsg == WM_SETCURSOR) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message)
+#define MSG_WM_MOUSEACTIVATE(func) \
+ if (uMsg == WM_MOUSEACTIVATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChildActivate()
+#define MSG_WM_CHILDACTIVATE(func) \
+ if (uMsg == WM_CHILDACTIVATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI)
+#define MSG_WM_GETMINMAXINFO(func) \
+ if (uMsg == WM_GETMINMAXINFO) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((LPMINMAXINFO)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnIconEraseBkgnd(CDCHandle dc)
+#define MSG_WM_ICONERASEBKGND(func) \
+ if (uMsg == WM_ICONERASEBKGND) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSpoolerStatus(UINT nStatus, UINT nJobs)
+#define MSG_WM_SPOOLERSTATUS(func) \
+ if (uMsg == WM_SPOOLERSTATUS) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (UINT)LOWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define MSG_WM_DRAWITEM(func) \
+ if (uMsg == WM_DRAWITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+#define MSG_WM_MEASUREITEM(func) \
+ if (uMsg == WM_MEASUREITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define MSG_WM_DELETEITEM(func) \
+ if (uMsg == WM_DELETEITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+//int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define MSG_WM_CHARTOITEM(func) \
+ if (uMsg == WM_CHARTOITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define MSG_WM_VKEYTOITEM(func) \
+ if (uMsg == WM_VKEYTOITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HCURSOR OnQueryDragIcon()
+#define MSG_WM_QUERYDRAGICON(func) \
+ if (uMsg == WM_QUERYDRAGICON) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+#define MSG_WM_COMPAREITEM(func) \
+ if (uMsg == WM_COMPAREITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCompacting(UINT nCpuTime)
+#define MSG_WM_COMPACTING(func) \
+ if (uMsg == WM_COMPACTING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct)
+#define MSG_WM_NCCREATE(func) \
+ if (uMsg == WM_NCCREATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcDestroy()
+#define MSG_WM_NCDESTROY(func) \
+ if (uMsg == WM_NCDESTROY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam)
+#define MSG_WM_NCCALCSIZE(func) \
+ if (uMsg == WM_NCCALCSIZE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((BOOL)wParam, lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnNcHitTest(CPoint point)
+#define MSG_WM_NCHITTEST(func) \
+ if (uMsg == WM_NCHITTEST) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcPaint(CRgnHandle rgn)
+#define MSG_WM_NCPAINT(func) \
+ if (uMsg == WM_NCPAINT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HRGN)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcActivate(BOOL bActive)
+#define MSG_WM_NCACTIVATE(func) \
+ if (uMsg == WM_NCACTIVATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((BOOL)wParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnGetDlgCode(LPMSG lpMsg)
+#define MSG_WM_GETDLGCODE(func) \
+ if (uMsg == WM_GETDLGCODE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMouseMove(UINT nHitTest, CPoint point)
+#define MSG_WM_NCMOUSEMOVE(func) \
+ if (uMsg == WM_NCMOUSEMOVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDown(UINT nHitTest, CPoint point)
+#define MSG_WM_NCLBUTTONDOWN(func) \
+ if (uMsg == WM_NCLBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonUp(UINT nHitTest, CPoint point)
+#define MSG_WM_NCLBUTTONUP(func) \
+ if (uMsg == WM_NCLBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDblClk(UINT nHitTest, CPoint point)
+#define MSG_WM_NCLBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCLBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDown(UINT nHitTest, CPoint point)
+#define MSG_WM_NCRBUTTONDOWN(func) \
+ if (uMsg == WM_NCRBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonUp(UINT nHitTest, CPoint point)
+#define MSG_WM_NCRBUTTONUP(func) \
+ if (uMsg == WM_NCRBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDblClk(UINT nHitTest, CPoint point)
+#define MSG_WM_NCRBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCRBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDown(UINT nHitTest, CPoint point)
+#define MSG_WM_NCMBUTTONDOWN(func) \
+ if (uMsg == WM_NCMBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonUp(UINT nHitTest, CPoint point)
+#define MSG_WM_NCMBUTTONUP(func) \
+ if (uMsg == WM_NCMBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDblClk(UINT nHitTest, CPoint point)
+#define MSG_WM_NCMBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCMBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_KEYDOWN(func) \
+ if (uMsg == WM_KEYDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_KEYUP(func) \
+ if (uMsg == WM_KEYUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_CHAR(func) \
+ if (uMsg == WM_CHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_DEADCHAR(func) \
+ if (uMsg == WM_DEADCHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_SYSKEYDOWN(func) \
+ if (uMsg == WM_SYSKEYDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_SYSKEYUP(func) \
+ if (uMsg == WM_SYSKEYUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_SYSCHAR(func) \
+ if (uMsg == WM_SYSCHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_SYSDEADCHAR(func) \
+ if (uMsg == WM_SYSDEADCHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysCommand(UINT nID, LPARAM lParam)
+#define MSG_WM_SYSCOMMAND(func) \
+ if (uMsg == WM_SYSCOMMAND) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTCard(UINT idAction, DWORD dwActionData)
+#define MSG_WM_TCARD(func) \
+ if (uMsg == WM_TCARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimer(UINT_PTR nIDEvent)
+#define MSG_WM_TIMER(func) \
+ if (uMsg == WM_TIMER) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT_PTR)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_WM_HSCROLL(func) \
+ if (uMsg == WM_HSCROLL) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_WM_VSCROLL(func) \
+ if (uMsg == WM_VSCROLL) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenu(CMenuHandle menu)
+#define MSG_WM_INITMENU(func) \
+ if (uMsg == WM_INITMENU) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenuPopup(CMenuHandle menuPopup, UINT nIndex, BOOL bSysMenu)
+#define MSG_WM_INITMENUPOPUP(func) \
+ if (uMsg == WM_INITMENUPOPUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenuHandle menu)
+#define MSG_WM_MENUSELECT(func) \
+ if (uMsg == WM_MENUSELECT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenuHandle menu)
+#define MSG_WM_MENUCHAR(func) \
+ if (uMsg == WM_MENUCHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh)
+#define MSG_WM_NOTIFY(func) \
+ if (uMsg == WM_NOTIFY) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterIdle(UINT nWhy, CWindow wndWho)
+#define MSG_WM_ENTERIDLE(func) \
+ if (uMsg == WM_ENTERIDLE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseMove(UINT nFlags, CPoint point)
+#define MSG_WM_MOUSEMOVE(func) \
+ if (uMsg == WM_MOUSEMOVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+#define MSG_WM_MOUSEWHEEL(func) \
+ if (uMsg == WM_MOUSEWHEEL) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDown(UINT nFlags, CPoint point)
+#define MSG_WM_LBUTTONDOWN(func) \
+ if (uMsg == WM_LBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonUp(UINT nFlags, CPoint point)
+#define MSG_WM_LBUTTONUP(func) \
+ if (uMsg == WM_LBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDblClk(UINT nFlags, CPoint point)
+#define MSG_WM_LBUTTONDBLCLK(func) \
+ if (uMsg == WM_LBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDown(UINT nFlags, CPoint point)
+#define MSG_WM_RBUTTONDOWN(func) \
+ if (uMsg == WM_RBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonUp(UINT nFlags, CPoint point)
+#define MSG_WM_RBUTTONUP(func) \
+ if (uMsg == WM_RBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDblClk(UINT nFlags, CPoint point)
+#define MSG_WM_RBUTTONDBLCLK(func) \
+ if (uMsg == WM_RBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDown(UINT nFlags, CPoint point)
+#define MSG_WM_MBUTTONDOWN(func) \
+ if (uMsg == WM_MBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonUp(UINT nFlags, CPoint point)
+#define MSG_WM_MBUTTONUP(func) \
+ if (uMsg == WM_MBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDblClk(UINT nFlags, CPoint point)
+#define MSG_WM_MBUTTONDBLCLK(func) \
+ if (uMsg == WM_MBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define MSG_WM_PARENTNOTIFY(func) \
+ if (uMsg == WM_PARENTNOTIFY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate)
+#define MSG_WM_MDIACTIVATE(func) \
+ if (uMsg == WM_MDIACTIVATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderFormat(UINT nFormat)
+#define MSG_WM_RENDERFORMAT(func) \
+ if (uMsg == WM_RENDERFORMAT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderAllFormats()
+#define MSG_WM_RENDERALLFORMATS(func) \
+ if (uMsg == WM_RENDERALLFORMATS) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroyClipboard()
+#define MSG_WM_DESTROYCLIPBOARD(func) \
+ if (uMsg == WM_DESTROYCLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawClipboard()
+#define MSG_WM_DRAWCLIPBOARD(func) \
+ if (uMsg == WM_DRAWCLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct)
+#define MSG_WM_PAINTCLIPBOARD(func) \
+ if (uMsg == WM_PAINTCLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define MSG_WM_VSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_VSCROLLCLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnContextMenu(CWindow wnd, CPoint point)
+#define MSG_WM_CONTEXTMENU(func) \
+ if (uMsg == WM_CONTEXTMENU) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect)
+#define MSG_WM_SIZECLIPBOARD(func) \
+ if (uMsg == WM_SIZECLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString)
+#define MSG_WM_ASKCBFORMATNAME(func) \
+ if (uMsg == WM_ASKCBFORMATNAME) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (LPTSTR)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter)
+#define MSG_WM_CHANGECBCHAIN(func) \
+ if (uMsg == WM_CHANGECBCHAIN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define MSG_WM_HSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_HSCROLLCLIPBOARD) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryNewPalette()
+#define MSG_WM_QUERYNEWPALETTE(func) \
+ if (uMsg == WM_QUERYNEWPALETTE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteChanged(CWindow wndFocus)
+#define MSG_WM_PALETTECHANGED(func) \
+ if (uMsg == WM_PALETTECHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteIsChanging(CWindow wndPalChg)
+#define MSG_WM_PALETTEISCHANGING(func) \
+ if (uMsg == WM_PALETTEISCHANGING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDropFiles(HDROP hDropInfo)
+#define MSG_WM_DROPFILES(func) \
+ if (uMsg == WM_DROPFILES) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HDROP)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanging(LPWINDOWPOS lpWndPos)
+#define MSG_WM_WINDOWPOSCHANGING(func) \
+ if (uMsg == WM_WINDOWPOSCHANGING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanged(LPWINDOWPOS lpWndPos)
+#define MSG_WM_WINDOWPOSCHANGED(func) \
+ if (uMsg == WM_WINDOWPOSCHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitMenuLoop(BOOL fIsTrackPopupMenu)
+#define MSG_WM_EXITMENULOOP(func) \
+ if (uMsg == WM_EXITMENULOOP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu)
+#define MSG_WM_ENTERMENULOOP(func) \
+ if (uMsg == WM_ENTERMENULOOP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define MSG_WM_STYLECHANGED(func) \
+ if (uMsg == WM_STYLECHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define MSG_WM_STYLECHANGING(func) \
+ if (uMsg == WM_STYLECHANGING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizing(UINT fwSide, LPRECT pRect)
+#define MSG_WM_SIZING(func) \
+ if (uMsg == WM_SIZING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMoving(UINT fwSide, LPRECT pRect)
+#define MSG_WM_MOVING(func) \
+ if (uMsg == WM_MOVING) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCaptureChanged(CWindow wnd)
+#define MSG_WM_CAPTURECHANGED(func) \
+ if (uMsg == WM_CAPTURECHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnDeviceChange(UINT nEventType, DWORD dwData)
+#define MSG_WM_DEVICECHANGE(func) \
+ if (uMsg == WM_DEVICECHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (DWORD)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define MSG_WM_COMMAND(func) \
+ if (uMsg == WM_COMMAND) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDisplayChange(UINT uBitsPerPixel, CSize sizeScreen)
+#define MSG_WM_DISPLAYCHANGE(func) \
+ if (uMsg == WM_DISPLAYCHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterSizeMove()
+#define MSG_WM_ENTERSIZEMOVE(func) \
+ if (uMsg == WM_ENTERSIZEMOVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitSizeMove()
+#define MSG_WM_EXITSIZEMOVE(func) \
+ if (uMsg == WM_EXITSIZEMOVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HFONT OnGetFont()
+#define MSG_WM_GETFONT(func) \
+ if (uMsg == WM_GETFONT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnGetHotKey()
+#define MSG_WM_GETHOTKEY(func) \
+ if (uMsg == WM_GETHOTKEY) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnGetIcon()
+#define MSG_WM_GETICON(func) \
+ if (uMsg == WM_GETICON) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetText(int cchTextMax, LPTSTR lpszText)
+#define MSG_WM_GETTEXT(func) \
+ if (uMsg == WM_GETTEXT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetTextLength()
+#define MSG_WM_GETTEXTLENGTH(func) \
+ if (uMsg == WM_GETTEXTLENGTH) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHelp(LPHELPINFO lpHelpInfo)
+#define MSG_WM_HELP(func) \
+ if (uMsg == WM_HELP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((LPHELPINFO)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey)
+#define MSG_WM_HOTKEY(func) \
+ if (uMsg == WM_HOTKEY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout)
+#define MSG_WM_INPUTLANGCHANGE(func) \
+ if (uMsg == WM_INPUTLANGCHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (HKL)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout)
+#define MSG_WM_INPUTLANGCHANGEREQUEST(func) \
+ if (uMsg == WM_INPUTLANGCHANGEREQUEST) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (HKL)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus)
+#define MSG_WM_NEXTDLGCTL(func) \
+ if (uMsg == WM_NEXTDLGCTL) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)LOWORD(lParam), wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu)
+#define MSG_WM_NEXTMENU(func) \
+ if (uMsg == WM_NEXTMENU) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (LPMDINEXTMENU)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnNotifyFormat(CWindow wndFrom, int nCommand)
+#define MSG_WM_NOTIFYFORMAT(func) \
+ if (uMsg == WM_NOTIFYFORMAT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (int)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD dwData)
+#define MSG_WM_POWERBROADCAST(func) \
+ if (uMsg == WM_POWERBROADCAST) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((DWORD)wParam, (DWORD)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrint(CDCHandle dc, UINT uFlags)
+#define MSG_WM_PRINT(func) \
+ if (uMsg == WM_PRINT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrintClient(CDCHandle dc, UINT uFlags)
+#define MSG_WM_PRINTCLIENT(func) \
+ if (uMsg == WM_PRINTCLIENT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError)
+#define MSG_WM_RASDIALEVENT(func) \
+ if (uMsg == WM_RASDIALEVENT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((RASCONNSTATE)wParam, (DWORD)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFont(CFontHandle font, BOOL bRedraw)
+#define MSG_WM_SETFONT(func) \
+ if (uMsg == WM_SETFONT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((HFONT)wParam, (BOOL)LOWORD(lParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetHotKey(int nVirtKey, UINT uFlags)
+#define MSG_WM_SETHOTKEY(func) \
+ if (uMsg == WM_SETHOTKEY) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), (UINT)HIBYTE(LOWORD(wParam))); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnSetIcon(UINT uType, HICON hIcon)
+#define MSG_WM_SETICON(func) \
+ if (uMsg == WM_SETICON) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetRedraw(BOOL bRedraw)
+#define MSG_WM_SETREDRAW(func) \
+ if (uMsg == WM_SETREDRAW) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetText(LPCTSTR lpstrText)
+#define MSG_WM_SETTEXT(func) \
+ if (uMsg == WM_SETTEXT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCTSTR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUserChanged()
+#define MSG_WM_USERCHANGED(func) \
+ if (uMsg == WM_USERCHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// New NT4 & NT5 messages
+
+#if(_WIN32_WINNT >= 0x0400)
+
+// void OnMouseHover(WPARAM wParam, CPoint ptPos)
+#define MSG_WM_MOUSEHOVER(func) \
+ if (uMsg == WM_MOUSEHOVER) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseLeave()
+#define MSG_WM_MOUSELEAVE(func) \
+ if (uMsg == WM_MOUSELEAVE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0400 */
+
+#if(WINVER >= 0x0500)
+
+// void OnMenuRButtonUp(WPARAM wParam, CMenuHandle menu)
+#define MSG_WM_MENURBUTTONUP(func) \
+ if (uMsg == WM_MENURBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuDrag(WPARAM wParam, CMenuHandle menu)
+#define MSG_WM_MENUDRAG(func) \
+ if (uMsg == WM_MENUDRAG) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(wParam, (HMENU)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info)
+#define MSG_WM_MENUGETOBJECT(func) \
+ if (uMsg == WM_MENUGETOBJECT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((PMENUGETOBJECTINFO)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUnInitMenuPopup(UINT nID, CMenuHandle menu)
+#define MSG_WM_UNINITMENUPOPUP(func) \
+ if (uMsg == WM_UNINITMENUPOPUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(lParam), (HMENU)wParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuCommand(WPARAM nIndex, CMenuHandle menu)
+#define MSG_WM_MENUCOMMAND(func) \
+ if (uMsg == WM_MENUCOMMAND) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* WINVER >= 0x0500 */
+
+#if(_WIN32_WINNT >= 0x0500)
+
+// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys)
+#define MSG_WM_APPCOMMAND(func) \
+ if (uMsg == WM_APPCOMMAND) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos)
+#define MSG_WM_NCXBUTTONDOWN(func) \
+ if (uMsg == WM_NCXBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos)
+#define MSG_WM_NCXBUTTONUP(func) \
+ if (uMsg == WM_NCXBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos)
+#define MSG_WM_NCXBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCXBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos)
+#define MSG_WM_XBUTTONDOWN(func) \
+ if (uMsg == WM_XBUTTONDOWN) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos)
+#define MSG_WM_XBUTTONUP(func) \
+ if (uMsg == WM_XBUTTONUP) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos)
+#define MSG_WM_XBUTTONDBLCLK(func) \
+ if (uMsg == WM_XBUTTONDBLCLK) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeUIState(WORD nAction, WORD nState)
+#define MSG_WM_CHANGEUISTATE(func) \
+ if (uMsg == WM_CHANGEUISTATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUpdateUIState(WORD nAction, WORD nState)
+#define MSG_WM_UPDATEUISTATE(func) \
+ if (uMsg == WM_UPDATEUISTATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnQueryUIState()
+#define MSG_WM_QUERYUISTATE(func) \
+ if (uMsg == WM_QUERYUISTATE) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif // (_WIN32_WINNT >= 0x0500)
+
+#if(_WIN32_WINNT >= 0x0501)
+
+// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput)
+#define MSG_WM_INPUT(func) \
+ if (uMsg == WM_INPUT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags)
+#define MSG_WM_UNICHAR(func) \
+ if (uMsg == WM_UNICHAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ if(IsMsgHandled()) \
+ { \
+ lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \
+ return TRUE; \
+ } \
+ }
+
+// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION nSessionID)
+#define MSG_WM_WTSSESSION_CHANGE(func) \
+ if (uMsg == WM_WTSSESSION_CHANGE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// OnThemeChanged()
+#define MSG_WM_THEMECHANGED(func) \
+ if (uMsg == WM_THEMECHANGED) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0501 */
+
+///////////////////////////////////////////////////////////////////////////////
+// ATL defined messages
+
+// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData)
+#define MSG_WM_FORWARDMSG(func) \
+ if (uMsg == WM_FORWARDMSG) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Dialog specific messages
+
+// LRESULT OnDMGetDefID()
+#define MSG_DM_GETDEFID(func) \
+ if (uMsg == DM_GETDEFID) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMSetDefID(UINT DefID)
+#define MSG_DM_SETDEFID(func) \
+ if (uMsg == DM_SETDEFID) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMReposition()
+#define MSG_DM_REPOSITION(func) \
+ if (uMsg == DM_REPOSITION) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Reflected messages
+
+// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define MSG_OCM_COMMAND(func) \
+ if (uMsg == OCM_COMMAND) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh)
+#define MSG_OCM_NOTIFY(func) \
+ if (uMsg == OCM_NOTIFY) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define MSG_OCM_PARENTNOTIFY(func) \
+ if (uMsg == OCM_PARENTNOTIFY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define MSG_OCM_DRAWITEM(func) \
+ if (uMsg == OCM_DRAWITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+#define MSG_OCM_MEASUREITEM(func) \
+ if (uMsg == OCM_MEASUREITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+#define MSG_OCM_COMPAREITEM(func) \
+ if (uMsg == OCM_COMPAREITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define MSG_OCM_DELETEITEM(func) \
+ if (uMsg == OCM_DELETEITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define MSG_OCM_VKEYTOITEM(func) \
+ if (uMsg == OCM_VKEYTOITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+//int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define MSG_OCM_CHARTOITEM(func) \
+ if (uMsg == OCM_CHARTOITEM) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_HSCROLL(func) \
+ if (uMsg == OCM_HSCROLL) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_VSCROLL(func) \
+ if (uMsg == OCM_VSCROLL) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit)
+#define MSG_OCM_CTLCOLOREDIT(func) \
+ if (uMsg == OCM_CTLCOLOREDIT) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define MSG_OCM_CTLCOLORLISTBOX(func) \
+ if (uMsg == OCM_CTLCOLORLISTBOX) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button)
+#define MSG_OCM_CTLCOLORBTN(func) \
+ if (uMsg == OCM_CTLCOLORBTN) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define MSG_OCM_CTLCOLORDLG(func) \
+ if (uMsg == OCM_CTLCOLORDLG) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define MSG_OCM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == OCM_CTLCOLORSCROLLBAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define MSG_OCM_CTLCOLORSTATIC(func) \
+ if (uMsg == OCM_CTLCOLORSTATIC) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Edit specific messages
+
+// void OnClear()
+#define MSG_WM_CLEAR(func) \
+ if (uMsg == WM_CLEAR) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCopy()
+#define MSG_WM_COPY(func) \
+ if (uMsg == WM_COPY) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCut()
+#define MSG_WM_CUT(func) \
+ if (uMsg == WM_CUT) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaste()
+#define MSG_WM_PASTE(func) \
+ if (uMsg == WM_PASTE) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUndo()
+#define MSG_WM_UNDO(func) \
+ if (uMsg == WM_UNDO) \
+ { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Generic message handlers
+
+// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define MESSAGE_HANDLER_EX(msg, func) \
+ if(uMsg == msg) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \
+ if(uMsg >= msgFirst && uMsg <= msgLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Commands and notifications
+
+// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh)
+#define NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh)
+#define NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \
+ if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define REFLECTED_COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh)
+#define REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh)
+#define REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \
+ if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if(IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif // __ATLCRACK_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLCTRLS_H__
+#define __ATLCTRLS_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlctrls.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlctrls.h requires atlwin.h to be included first
+#endif
+
+#ifndef _WIN32_WCE
+ #include <richedit.h>
+ #include <richole.h>
+#elif defined(WIN32_PLATFORM_WFSP) && !defined(_WINUSERM_H_)
+ #include <winuserm.h>
+#endif // !_WIN32_WCE
+
+// protect template members from windowsx.h macros
+#ifdef _INC_WINDOWSX
+ #undef GetNextSibling
+ #undef GetPrevSibling
+#endif // _INC_WINDOWSX
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CStaticT<TBase> - CStatic
+// CButtonT<TBase> - CButton
+// CListBoxT<TBase> - CListBox
+// CComboBoxT<TBase> - CComboBox
+// CEditT<TBase> - CEdit
+// CEditCommands<T>
+// CScrollBarT<TBase> - CScrollBar
+//
+// CImageList
+// CListViewCtrlT<TBase> - CListViewCtrl
+// CTreeViewCtrlT<TBase> - CTreeViewCtrl
+// CTreeItemT<TBase> - CTreeItem
+// CTreeViewCtrlExT<TBase> - CTreeViewCtrlEx
+// CHeaderCtrlT<TBase> - CHeaderCtrl
+// CToolBarCtrlT<TBase> - CToolBarCtrl
+// CStatusBarCtrlT<TBase> - CStatusBarCtrl
+// CTabCtrlT<TBase> - CTabCtrl
+// CToolInfo
+// CToolTipCtrlT<TBase> - CToolTipCtrl
+// CTrackBarCtrlT<TBase> - CTrackBarCtrl
+// CUpDownCtrlT<TBase> - CUpDownCtrl
+// CProgressBarCtrlT<TBase> - CProgressBarCtrl
+// CHotKeyCtrlT<TBase> - CHotKeyCtrl
+// CAnimateCtrlT<TBase> - CAnimateCtrl
+// CRichEditCtrlT<TBase> - CRichEditCtrl
+// CRichEditCommands<T>
+// CDragListBoxT<TBase> - CDragListBox
+// CDragListNotifyImpl<T>
+// CReBarCtrlT<TBase> - CReBarCtrl
+// CComboBoxExT<TBase> - CComboBoxEx
+// CDateTimePickerCtrlT<TBase> - CDateTimePickerCtrl
+// CMonthCalendarCtrlT<TBase> - CMonthCalendarCtrl
+// CFlatScrollBarImpl<T>
+// CFlatScrollBarT<TBase> - CFlatScrollBar
+// CIPAddressCtrlT<TBase> - CIPAddressCtrl
+// CPagerCtrlT<TBase> - CPagerCtrl
+// CLinkCtrlT<TBase> - CLinkCtrl
+//
+// CCustomDraw<T>
+//
+// CCECommandBarCtrlT<TBase> - CCECommandBarCtrl
+// CCECommandBandsCtrlT<TBase> - CCECommandBandsCtrl
+
+
+namespace WTL
+{
+
+// These are wrapper classes for Windows standard and common controls.
+// To implement a window based on a control, use following:
+// Example: Implementing a window based on a list box
+//
+// class CMyListBox : CWindowImpl<CMyListBox, CListBox>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyListBox)
+// // put your message handler entries here
+// END_MSG_MAP()
+// };
+
+
+
+// --- Standard Windows controls ---
+
+///////////////////////////////////////////////////////////////////////////////
+// CStatic - client side for a Windows STATIC control
+
+template <class TBase>
+class CStaticT : public TBase
+{
+public:
+// Constructors
+ CStaticT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CStaticT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("STATIC");
+ }
+
+#ifndef _WIN32_WCE
+ HICON GetIcon() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, STM_GETICON, 0, 0L);
+ }
+
+ HICON SetIcon(HICON hIcon)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, STM_SETICON, (WPARAM)hIcon, 0L);
+ }
+
+ HENHMETAFILE GetEnhMetaFile() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HENHMETAFILE)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ENHMETAFILE, 0L);
+ }
+
+ HENHMETAFILE SetEnhMetaFile(HENHMETAFILE hMetaFile)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HENHMETAFILE)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)hMetaFile);
+ }
+#else // CE specific
+ HICON GetIcon() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ICON, 0L);
+ }
+
+ HICON SetIcon(HICON hIcon)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
+ }
+#endif // _WIN32_WCE
+
+ CBitmapHandle GetBitmap() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0L));
+ }
+
+ CBitmapHandle SetBitmap(HBITMAP hBitmap)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap));
+ }
+
+ HCURSOR GetCursor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HCURSOR)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_CURSOR, 0L);
+ }
+
+ HCURSOR SetCursor(HCURSOR hCursor)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HCURSOR)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor);
+ }
+};
+
+typedef CStaticT<ATL::CWindow> CStatic;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CButton - client side for a Windows BUTTON control
+
+template <class TBase>
+class CButtonT : public TBase
+{
+public:
+// Constructors
+ CButtonT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CButtonT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("BUTTON");
+ }
+
+ UINT GetState() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L);
+ }
+
+ void SetState(BOOL bHighlight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L);
+ }
+
+ int GetCheck() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0L);
+ }
+
+ void SetCheck(int nCheck)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0L);
+ }
+
+ UINT GetButtonStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::GetWindowLong(m_hWnd, GWL_STYLE) & 0xFFFF;
+ }
+
+ void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw);
+ }
+
+#ifndef _WIN32_WCE
+ HICON GetIcon() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L);
+ }
+
+ HICON SetIcon(HICON hIcon)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
+ }
+
+ CBitmapHandle GetBitmap() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L));
+ }
+
+ CBitmapHandle SetBitmap(HBITMAP hBitmap)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap));
+ }
+#endif // !_WIN32_WCE
+
+#if (_WIN32_WINNT >= 0x0501)
+ BOOL GetIdealSize(LPSIZE lpSize) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, BCM_GETIDEALSIZE, 0, (LPARAM)lpSize);
+ }
+
+ BOOL GetImageList(PBUTTON_IMAGELIST pButtonImagelist) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, BCM_GETIMAGELIST, 0, (LPARAM)pButtonImagelist);
+ }
+
+ BOOL SetImageList(PBUTTON_IMAGELIST pButtonImagelist)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, BCM_SETIMAGELIST, 0, (LPARAM)pButtonImagelist);
+ }
+
+ BOOL GetTextMargin(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, BCM_GETTEXTMARGIN, 0, (LPARAM)lpRect);
+ }
+
+ BOOL SetTextMargin(LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, BCM_SETTEXTMARGIN, 0, (LPARAM)lpRect);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (WINVER >= 0x0600)
+ void SetDontClick(BOOL bDontClick)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, BM_SETDONTCLICK, (WPARAM)bDontClick, 0L);
+ }
+#endif // (WINVER >= 0x0600)
+
+#if (_WIN32_WINNT >= 0x0600)
+ BOOL SetDropDownState(BOOL bDropDown)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);
+ return (BOOL)::SendMessage(m_hWnd, BCM_SETDROPDOWNSTATE, (WPARAM)bDropDown, 0L);
+ }
+
+ BOOL GetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);
+ return (BOOL)::SendMessage(m_hWnd, BCM_GETSPLITINFO, 0, (LPARAM)pSplitInfo);
+ }
+
+ BOOL SetSplitInfo(PBUTTON_SPLITINFO pSplitInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);
+ return (BOOL)::SendMessage(m_hWnd, BCM_SETSPLITINFO, 0, (LPARAM)pSplitInfo);
+ }
+
+ int GetNoteLength() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);
+ return (int)::SendMessage(m_hWnd, BCM_GETNOTELENGTH, 0, 0L);
+ }
+
+ BOOL GetNote(LPWSTR lpstrNoteText, int cchNoteText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);
+ return (BOOL)::SendMessage(m_hWnd, BCM_GETNOTE, cchNoteText, (LPARAM)lpstrNoteText);
+ }
+
+ BOOL SetNote(LPCWSTR lpstrNoteText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);
+ return (BOOL)::SendMessage(m_hWnd, BCM_SETNOTE, 0, (LPARAM)lpstrNoteText);
+ }
+
+ LRESULT SetElevationRequiredState(BOOL bSet)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::SendMessage(m_hWnd, BCM_SETSHIELD, 0, (LPARAM)bSet);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ void Click()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, BM_CLICK, 0, 0L);
+ }
+};
+
+typedef CButtonT<ATL::CWindow> CButton;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CListBox - client side for a Windows LISTBOX control
+
+template <class TBase>
+class CListBoxT : public TBase
+{
+public:
+// Constructors
+ CListBoxT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CListBoxT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("LISTBOX");
+ }
+
+ // for entire listbox
+ int GetCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETCOUNT, 0, 0L);
+ }
+
+#ifndef _WIN32_WCE
+ int SetCount(int cItems)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(((GetStyle() & LBS_NODATA) != 0) && ((GetStyle() & LBS_HASSTRINGS) == 0));
+ return (int)::SendMessage(m_hWnd, LB_SETCOUNT, cItems, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ int GetHorizontalExtent() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETHORIZONTALEXTENT, 0, 0L);
+ }
+
+ void SetHorizontalExtent(int cxExtent)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LB_SETHORIZONTALEXTENT, cxExtent, 0L);
+ }
+
+ int GetTopIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETTOPINDEX, 0, 0L);
+ }
+
+ int SetTopIndex(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_SETTOPINDEX, nIndex, 0L);
+ }
+
+ LCID GetLocale() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LCID)::SendMessage(m_hWnd, LB_GETLOCALE, 0, 0L);
+ }
+
+ LCID SetLocale(LCID nNewLocale)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LCID)::SendMessage(m_hWnd, LB_SETLOCALE, (WPARAM)nNewLocale, 0L);
+ }
+
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ DWORD GetListBoxInfo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if (_WIN32_WINNT >= 0x0501)
+ return (DWORD)::SendMessage(m_hWnd, LB_GETLISTBOXINFO, 0, 0L);
+#else // !(_WIN32_WINNT >= 0x0501)
+ return ::GetListBoxInfo(m_hWnd);
+#endif // !(_WIN32_WINNT >= 0x0501)
+ }
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+
+ // for single-selection listboxes
+ int GetCurSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);
+ return (int)::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L);
+ }
+
+ int SetCurSel(int nSelect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);
+ return (int)::SendMessage(m_hWnd, LB_SETCURSEL, nSelect, 0L);
+ }
+
+ // for multiple-selection listboxes
+ int GetSel(int nIndex) const // also works for single-selection
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETSEL, nIndex, 0L);
+ }
+
+ int SetSel(int nIndex, BOOL bSelect = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ return (int)::SendMessage(m_hWnd, LB_SETSEL, bSelect, nIndex);
+ }
+
+ int GetSelCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ return (int)::SendMessage(m_hWnd, LB_GETSELCOUNT, 0, 0L);
+ }
+
+ int GetSelItems(int nMaxItems, LPINT rgIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ return (int)::SendMessage(m_hWnd, LB_GETSELITEMS, nMaxItems, (LPARAM)rgIndex);
+ }
+
+ int GetAnchorIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ return (int)::SendMessage(m_hWnd, LB_GETANCHORINDEX, 0, 0L);
+ }
+
+ void SetAnchorIndex(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ ::SendMessage(m_hWnd, LB_SETANCHORINDEX, nIndex, 0L);
+ }
+
+ int GetCaretIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETCARETINDEX, 0, 0);
+ }
+
+ int SetCaretIndex(int nIndex, BOOL bScroll = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_SETCARETINDEX, nIndex, MAKELONG(bScroll, 0));
+ }
+
+ // for listbox items
+ DWORD_PTR GetItemData(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD_PTR)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L);
+ }
+
+ int SetItemData(int nIndex, DWORD_PTR dwItemData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_SETITEMDATA, nIndex, (LPARAM)dwItemData);
+ }
+
+ void* GetItemDataPtr(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (void*)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L);
+ }
+
+ int SetItemDataPtr(int nIndex, void* pData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItemData(nIndex, (DWORD_PTR)pData);
+ }
+
+ int GetItemRect(int nIndex, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETITEMRECT, nIndex, (LPARAM)lpRect);
+ }
+
+ int GetText(int nIndex, LPTSTR lpszBuffer) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETTEXT, nIndex, (LPARAM)lpszBuffer);
+ }
+
+#ifndef _ATL_NO_COM
+#ifdef _OLEAUTO_H_
+ BOOL GetTextBSTR(int nIndex, BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+
+ int nLen = GetTextLen(nIndex);
+ if(nLen == LB_ERR)
+ return FALSE;
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(nLen + 1);
+ if(lpstrText == NULL)
+ return FALSE;
+
+ if(GetText(nIndex, lpstrText) == LB_ERR)
+ return FALSE;
+
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // _OLEAUTO_H_
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetText(int nIndex, _CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int cchLen = GetTextLen(nIndex);
+ if(cchLen == LB_ERR)
+ return LB_ERR;
+ int nRet = LB_ERR;
+ LPTSTR lpstr = strText.GetBufferSetLength(cchLen);
+ if(lpstr != NULL)
+ {
+ nRet = GetText(nIndex, lpstr);
+ strText.ReleaseBuffer();
+ }
+ return nRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ int GetTextLen(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETTEXTLEN, nIndex, 0L);
+ }
+
+ int GetItemHeight(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_GETITEMHEIGHT, nIndex, 0L);
+ }
+
+ int SetItemHeight(int nIndex, UINT cyItemHeight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0));
+ }
+
+ // Settable only attributes
+ void SetColumnWidth(int cxWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LB_SETCOLUMNWIDTH, cxWidth, 0L);
+ }
+
+ BOOL SetTabStops(int nTabStops, LPINT rgTabStops)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);
+ return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);
+ }
+
+ BOOL SetTabStops()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);
+ return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 0, 0L);
+ }
+
+ BOOL SetTabStops(const int& cxEachStop) // takes an 'int'
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);
+ return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);
+ }
+
+// Operations
+ int InitStorage(int nItems, UINT nBytes)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_INITSTORAGE, (WPARAM)nItems, nBytes);
+ }
+
+ void ResetContent()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LB_RESETCONTENT, 0, 0L);
+ }
+
+ UINT ItemFromPoint(POINT pt, BOOL& bOutside) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dw = (DWORD)::SendMessage(m_hWnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));
+ bOutside = (BOOL)HIWORD(dw);
+ return (UINT)LOWORD(dw);
+ }
+
+ // manipulating listbox items
+ int AddString(LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszItem);
+ }
+
+ int DeleteString(UINT nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_DELETESTRING, nIndex, 0L);
+ }
+
+ int InsertString(int nIndex, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_INSERTSTRING, nIndex, (LPARAM)lpszItem);
+ }
+
+#ifndef _WIN32_WCE
+ int Dir(UINT attr, LPCTSTR lpszWildCard)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_DIR, attr, (LPARAM)lpszWildCard);
+ }
+
+ int AddFile(LPCTSTR lpstrFileName)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_ADDFILE, 0, (LPARAM)lpstrFileName);
+ }
+#endif // !_WIN32_WCE
+
+ // selection helpers
+ int FindString(int nStartAfter, LPCTSTR lpszItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_FINDSTRING, nStartAfter, (LPARAM)lpszItem);
+ }
+
+ int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind);
+ }
+
+ int SelectString(int nStartAfter, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LB_SELECTSTRING, nStartAfter, (LPARAM)lpszItem);
+ }
+
+ int SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);
+ ATLASSERT(nFirstItem <= nLastItem);
+ return bSelect ? (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nFirstItem, nLastItem) : (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nLastItem, nFirstItem);
+ }
+
+#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages
+ DWORD GetInputMode(BOOL bCurrentMode = TRUE)
+ {
+ return SendMessage(LB_GETINPUTMODE, 0, (LPARAM)bCurrentMode);
+ }
+
+ BOOL SetInputMode(DWORD dwMode)
+ {
+ return SendMessage(LB_SETINPUTMODE, 0, (LPARAM)dwMode);
+ }
+#endif // WIN32_PLATFORM_WFSP
+};
+
+typedef CListBoxT<ATL::CWindow> CListBox;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CComboBox - client side for a Windows COMBOBOX control
+
+#ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones
+
+template <class TBase>
+class CComboBoxT : public TBase
+{
+public:
+// Constructors
+ CComboBoxT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CComboBoxT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("COMBOBOX");
+ }
+
+ // for entire combo box
+ int GetCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0L);
+ }
+
+ int GetCurSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0L);
+ }
+
+ int SetCurSel(int nSelect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0L);
+ }
+
+ LCID GetLocale() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LCID)::SendMessage(m_hWnd, CB_GETLOCALE, 0, 0L);
+ }
+
+ LCID SetLocale(LCID nNewLocale)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LCID)::SendMessage(m_hWnd, CB_SETLOCALE, (WPARAM)nNewLocale, 0L);
+ }
+
+ int GetTopIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETTOPINDEX, 0, 0L);
+ }
+
+ int SetTopIndex(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETTOPINDEX, nIndex, 0L);
+ }
+
+ UINT GetHorizontalExtent() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, CB_GETHORIZONTALEXTENT, 0, 0L);
+ }
+
+ void SetHorizontalExtent(UINT nExtent)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, CB_SETHORIZONTALEXTENT, nExtent, 0L);
+ }
+
+ int GetDroppedWidth() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETDROPPEDWIDTH, 0, 0L);
+ }
+
+ int SetDroppedWidth(UINT nWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETDROPPEDWIDTH, nWidth, 0L);
+ }
+
+#if ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))
+ BOOL GetComboBoxInfo(PCOMBOBOXINFO pComboBoxInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if ((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))
+ return (BOOL)::SendMessage(m_hWnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)pComboBoxInfo);
+#else // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))
+ return ::GetComboBoxInfo(m_hWnd, pComboBoxInfo);
+#endif // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))
+ }
+#endif // ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))
+
+ // for edit control
+ DWORD GetEditSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0L);
+ }
+
+ BOOL SetEditSel(int nStartChar, int nEndChar)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar));
+ }
+
+ // for combobox item
+ DWORD_PTR GetItemData(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD_PTR)::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0L);
+ }
+
+ int SetItemData(int nIndex, DWORD_PTR dwItemData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData);
+ }
+
+ void* GetItemDataPtr(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (void*)GetItemData(nIndex);
+ }
+
+ int SetItemDataPtr(int nIndex, void* pData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItemData(nIndex, (DWORD_PTR)pData);
+ }
+
+ int GetLBText(int nIndex, LPTSTR lpszText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETLBTEXT, nIndex, (LPARAM)lpszText);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetLBTextBSTR(int nIndex, BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+
+ int nLen = GetLBTextLen(nIndex);
+ if(nLen == CB_ERR)
+ return FALSE;
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(nLen + 1);
+ if(lpstrText == NULL)
+ return FALSE;
+
+ if(GetLBText(nIndex, lpstrText) == CB_ERR)
+ return FALSE;
+
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetLBText(int nIndex, _CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int cchLen = GetLBTextLen(nIndex);
+ if(cchLen == CB_ERR)
+ return CB_ERR;
+ int nRet = CB_ERR;
+ LPTSTR lpstr = strText.GetBufferSetLength(cchLen);
+ if(lpstr != NULL)
+ {
+ nRet = GetLBText(nIndex, lpstr);
+ strText.ReleaseBuffer();
+ }
+ return nRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ int GetLBTextLen(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETLBTEXTLEN, nIndex, 0L);
+ }
+
+ int GetItemHeight(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETITEMHEIGHT, nIndex, 0L);
+ }
+
+ int SetItemHeight(int nIndex, UINT cyItemHeight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0));
+ }
+
+ BOOL GetExtendedUI() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_GETEXTENDEDUI, 0, 0L);
+ }
+
+ int SetExtendedUI(BOOL bExtended = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SETEXTENDEDUI, bExtended, 0L);
+ }
+
+ void GetDroppedControlRect(LPRECT lprect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)lprect);
+ }
+
+ BOOL GetDroppedState() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_GETDROPPEDSTATE, 0, 0L);
+ }
+
+#if (_WIN32_WINNT >= 0x0501)
+ int GetMinVisible() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_GETMINVISIBLE, 0, 0L);
+ }
+
+ BOOL SetMinVisible(int nMinVisible)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_SETMINVISIBLE, nMinVisible, 0L);
+ }
+
+ // Vista only
+ BOOL GetCueBannerText(LPWSTR lpwText, int cchText) const
+ {
+#ifndef CB_GETCUEBANNER
+ const UINT CB_GETCUEBANNER = (CBM_FIRST + 4);
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_GETCUEBANNER, (WPARAM)lpwText, cchText);
+ }
+
+ // Vista only
+ BOOL SetCueBannerText(LPCWSTR lpcwText)
+ {
+#ifndef CB_SETCUEBANNER
+ const UINT CB_SETCUEBANNER = (CBM_FIRST + 3);
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_SETCUEBANNER, 0, (LPARAM)lpcwText);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+// Operations
+ int InitStorage(int nItems, UINT nBytes)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_INITSTORAGE, (WPARAM)nItems, nBytes);
+ }
+
+ void ResetContent()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, CB_RESETCONTENT, 0, 0L);
+ }
+
+ // for edit control
+ BOOL LimitText(int nMaxChars)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0L);
+ }
+
+ // for drop-down combo boxes
+ void ShowDropDown(BOOL bShowIt = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, CB_SHOWDROPDOWN, bShowIt, 0L);
+ }
+
+ // manipulating listbox items
+ int AddString(LPCTSTR lpszString)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0, (LPARAM)lpszString);
+ }
+
+ int DeleteString(UINT nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_DELETESTRING, nIndex, 0L);
+ }
+
+ int InsertString(int nIndex, LPCTSTR lpszString)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_INSERTSTRING, nIndex, (LPARAM)lpszString);
+ }
+
+#ifndef _WIN32_WCE
+ int Dir(UINT attr, LPCTSTR lpszWildCard)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_DIR, attr, (LPARAM)lpszWildCard);
+ }
+#endif // !_WIN32_WCE
+
+ // selection helpers
+ int FindString(int nStartAfter, LPCTSTR lpszString) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_FINDSTRING, nStartAfter, (LPARAM)lpszString);
+ }
+
+ int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind);
+ }
+
+ int SelectString(int nStartAfter, LPCTSTR lpszString)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CB_SELECTSTRING, nStartAfter, (LPARAM)lpszString);
+ }
+
+ // Clipboard operations
+ void Clear()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);
+ }
+
+ void Copy()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_COPY, 0, 0L);
+ }
+
+ void Cut()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CUT, 0, 0L);
+ }
+
+ void Paste()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_PASTE, 0, 0L);
+ }
+};
+
+typedef CComboBoxT<ATL::CWindow> CComboBox;
+
+#endif // !WIN32_PLATFORM_WFSP
+
+///////////////////////////////////////////////////////////////////////////////
+// CEdit - client side for a Windows EDIT control
+
+template <class TBase>
+class CEditT : public TBase
+{
+public:
+// Constructors
+ CEditT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CEditT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("EDIT");
+ }
+
+ BOOL CanUndo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);
+ }
+
+ int GetLineCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L);
+ }
+
+ BOOL GetModify() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);
+ }
+
+ void SetModify(BOOL bModified = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L);
+ }
+
+ void GetRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect);
+ }
+
+ DWORD GetSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L);
+ }
+
+ void GetSel(int& nStartChar, int& nEndChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
+ }
+
+#ifndef _WIN32_WCE
+ HLOCAL GetHandle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HLOCAL)::SendMessage(m_hWnd, EM_GETHANDLE, 0, 0L);
+ }
+
+ void SetHandle(HLOCAL hBuffer)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETHANDLE, (WPARAM)hBuffer, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ DWORD GetMargins() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L);
+ }
+
+ void SetMargins(UINT nLeft, UINT nRight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELONG(nLeft, nRight));
+ }
+
+ UINT GetLimitText() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L);
+ }
+
+ void SetLimitText(UINT nMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETLIMITTEXT, nMax, 0L);
+ }
+
+ POINT PosFromChar(UINT nChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_POSFROMCHAR, nChar, 0);
+ POINT point = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) };
+ return point;
+ }
+
+ int CharFromPos(POINT pt, int* pLine = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y));
+ if(pLine != NULL)
+ *pLine = (int)(short)HIWORD(dwRet);
+ return (int)(short)LOWORD(dwRet);
+ }
+
+ // NOTE: first word in lpszBuffer must contain the size of the buffer!
+ int GetLine(int nIndex, LPTSTR lpszBuffer) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
+ }
+
+ int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ *(LPWORD)lpszBuffer = (WORD)nMaxLength;
+ return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
+ }
+
+ TCHAR GetPasswordChar() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (TCHAR)::SendMessage(m_hWnd, EM_GETPASSWORDCHAR, 0, 0L);
+ }
+
+ void SetPasswordChar(TCHAR ch)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETPASSWORDCHAR, ch, 0L);
+ }
+
+#ifndef _WIN32_WCE
+ EDITWORDBREAKPROC GetWordBreakProc() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L);
+ }
+
+ void SetWordBreakProc(EDITWORDBREAKPROC ewbprc)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc);
+ }
+#endif // !_WIN32_WCE
+
+ int GetFirstVisibleLine() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);
+ }
+
+#ifndef _WIN32_WCE
+ int GetThumb() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & ES_MULTILINE) != 0);
+ return (int)::SendMessage(m_hWnd, EM_GETTHUMB, 0, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL SetReadOnly(BOOL bReadOnly = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L);
+ }
+
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ UINT GetImeStatus(UINT uStatus) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETIMESTATUS, uStatus, 0L);
+ }
+
+ UINT SetImeStatus(UINT uStatus, UINT uData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_SETIMESTATUS, uStatus, uData);
+ }
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501)
+ BOOL GetCueBannerText(LPCWSTR lpstrText, int cchText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETCUEBANNER, (WPARAM)lpstrText, cchText);
+ }
+
+ // bKeepWithFocus - Vista only
+ BOOL SetCueBannerText(LPCWSTR lpstrText, BOOL bKeepWithFocus = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCUEBANNER, (WPARAM)bKeepWithFocus, (LPARAM)(lpstrText));
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+// Operations
+ void EmptyUndoBuffer()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L);
+ }
+
+ BOOL FmtLines(BOOL bAddEOL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_FMTLINES, bAddEOL, 0L);
+ }
+
+ void LimitText(int nChars = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_LIMITTEXT, nChars, 0L);
+ }
+
+ int LineFromChar(int nIndex = -1) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_LINEFROMCHAR, nIndex, 0L);
+ }
+
+ int LineIndex(int nLine = -1) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L);
+ }
+
+ int LineLength(int nLine = -1) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L);
+ }
+
+ void LineScroll(int nLines, int nChars = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines);
+ }
+
+ void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText);
+ }
+
+ void SetRect(LPCRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect);
+ }
+
+ void SetRectNP(LPCRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect);
+ }
+
+ void SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection));
+ if(!bNoScroll)
+ ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);
+ }
+
+ void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar);
+ if(!bNoScroll)
+ ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);
+ }
+
+ void SetSelAll(BOOL bNoScroll = FALSE)
+ {
+ SetSel(0, -1, bNoScroll);
+ }
+
+ void SetSelNone(BOOL bNoScroll = FALSE)
+ {
+ SetSel(-1, 0, bNoScroll);
+ }
+
+ BOOL SetTabStops(int nTabStops, LPINT rgTabStops)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);
+ }
+
+ BOOL SetTabStops()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L);
+ }
+
+ BOOL SetTabStops(const int& cxEachStop) // takes an 'int'
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);
+ }
+
+ void ScrollCaret()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);
+ }
+
+ int Scroll(int nScrollAction)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & ES_MULTILINE) != 0);
+ LRESULT lRet = ::SendMessage(m_hWnd, EM_SCROLL, nScrollAction, 0L);
+ if(!(BOOL)HIWORD(lRet))
+ return -1; // failed
+ return (int)(short)LOWORD(lRet);
+
+ }
+
+ void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE)
+ {
+ SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll);
+ ReplaceSel(lpstrText, bCanUndo);
+ }
+
+ void AppendText(LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE)
+ {
+ InsertText(GetWindowTextLength(), lpstrText, bNoScroll, bCanUndo);
+ }
+
+#if (_WIN32_WINNT >= 0x0501)
+ BOOL ShowBalloonTip(PEDITBALLOONTIP pEditBaloonTip)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SHOWBALLOONTIP, 0, (LPARAM)pEditBaloonTip);
+ }
+
+ BOOL HideBalloonTip()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_HIDEBALLOONTIP, 0, 0L);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+ DWORD GetHilite() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L);
+ }
+
+ void GetHilite(int& nStartChar, int& nEndChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L);
+ nStartChar = (int)(short)LOWORD(dwRet);
+ nEndChar = (int)(short)HIWORD(dwRet);
+ }
+
+ void SetHilite(int nStartChar, int nEndChar)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETHILITE, nStartChar, nEndChar);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+ // Clipboard operations
+ BOOL Undo()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L);
+ }
+
+ void Clear()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);
+ }
+
+ void Copy()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_COPY, 0, 0L);
+ }
+
+ void Cut()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CUT, 0, 0L);
+ }
+
+ void Paste()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_PASTE, 0, 0L);
+ }
+
+#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages
+ DWORD GetExtendedStyle()
+ {
+ return SendMessage(EM_GETEXTENDEDSTYLE);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwMask, DWORD dwExStyle)
+ {
+ return SendMessage(EM_SETEXTENDEDSTYLE, (WPARAM)dwMask, (LPARAM)dwExStyle);
+ }
+
+ DWORD GetInputMode(BOOL bCurrentMode = TRUE)
+ {
+ return SendMessage(EM_GETINPUTMODE, 0, (LPARAM)bCurrentMode);
+ }
+
+ BOOL SetInputMode(DWORD dwMode)
+ {
+ return SendMessage(EM_SETINPUTMODE, 0, (LPARAM)dwMode);
+ }
+
+ BOOL SetSymbols(LPCTSTR szSymbols)
+ {
+ return SendMessage(EM_SETSYMBOLS, 0, (LPARAM)szSymbols);
+ }
+
+ BOOL ResetSymbols()
+ {
+ return SendMessage(EM_SETSYMBOLS);
+ }
+#endif // WIN32_PLATFORM_WFSP
+};
+
+typedef CEditT<ATL::CWindow> CEdit;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CEditCommands - message handlers for standard EDIT commands
+
+// Chain to CEditCommands message map. Your class must also derive from CEdit.
+// Example:
+// class CMyEdit : public CWindowImpl<CMyEdit, CEdit>,
+// public CEditCommands<CMyEdit>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyEdit)
+// // your handlers...
+// CHAIN_MSG_MAP_ALT(CEditCommands<CMyEdit>, 1)
+// END_MSG_MAP()
+// // other stuff...
+// };
+
+template <class T>
+class CEditCommands
+{
+public:
+ BEGIN_MSG_MAP(CEditCommands< T >)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear)
+ COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll)
+ COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy)
+ COMMAND_ID_HANDLER(ID_EDIT_CUT, OnEditCut)
+ COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste)
+ COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll)
+ COMMAND_ID_HANDLER(ID_EDIT_UNDO, OnEditUndo)
+ END_MSG_MAP()
+
+ LRESULT OnEditClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Clear();
+ return 0;
+ }
+
+ LRESULT OnEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetSel(0, -1);
+ pT->Clear();
+ return 0;
+ }
+
+ LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Copy();
+ return 0;
+ }
+
+ LRESULT OnEditCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Cut();
+ return 0;
+ }
+
+ LRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Paste();
+ return 0;
+ }
+
+ LRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetSel(0, -1);
+ return 0;
+ }
+
+ LRESULT OnEditUndo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Undo();
+ return 0;
+ }
+
+// State (update UI) helpers
+ BOOL CanCut() const
+ { return HasSelection(); }
+
+ BOOL CanCopy() const
+ { return HasSelection(); }
+
+ BOOL CanClear() const
+ { return HasSelection(); }
+
+ BOOL CanSelectAll() const
+ { return HasText(); }
+
+ BOOL CanFind() const
+ { return HasText(); }
+
+ BOOL CanRepeat() const
+ { return HasText(); }
+
+ BOOL CanReplace() const
+ { return HasText(); }
+
+ BOOL CanClearAll() const
+ { return HasText(); }
+
+// Implementation
+ BOOL HasSelection() const
+ {
+ const T* pT = static_cast<const T*>(this);
+ int nMin, nMax;
+ ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nMin, (LPARAM)&nMax);
+ return (nMin != nMax);
+ }
+
+ BOOL HasText() const
+ {
+ const T* pT = static_cast<const T*>(this);
+ return (pT->GetWindowTextLength() > 0);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScrollBar - client side for a Windows SCROLLBAR control
+
+template <class TBase>
+class CScrollBarT : public TBase
+{
+public:
+// Constructors
+ CScrollBarT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CScrollBarT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return _T("SCROLLBAR");
+ }
+
+#ifndef _WIN32_WCE
+ int GetScrollPos() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::GetScrollPos(m_hWnd, SB_CTL);
+ }
+#endif // !_WIN32_WCE
+
+ int SetScrollPos(int nPos, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::SetScrollPos(m_hWnd, SB_CTL, nPos, bRedraw);
+ }
+
+#ifndef _WIN32_WCE
+ void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::GetScrollRange(m_hWnd, SB_CTL, lpMinPos, lpMaxPos);
+ }
+#endif // !_WIN32_WCE
+
+ void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SetScrollRange(m_hWnd, SB_CTL, nMinPos, nMaxPos, bRedraw);
+ }
+
+ BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::GetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo);
+ }
+
+ int SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::SetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo, bRedraw);
+ }
+
+#ifndef _WIN32_WCE
+ int GetScrollLimit() const
+ {
+ int nMin = 0, nMax = 0;
+ ::GetScrollRange(m_hWnd, SB_CTL, &nMin, &nMax);
+ SCROLLINFO info = { 0 };
+ info.cbSize = sizeof(SCROLLINFO);
+ info.fMask = SIF_PAGE;
+ if(::GetScrollInfo(m_hWnd, SB_CTL, &info))
+ nMax -= ((info.nPage - 1) > 0) ? (info.nPage - 1) : 0;
+
+ return nMax;
+ }
+
+#if (WINVER >= 0x0500)
+ BOOL GetScrollBarInfo(PSCROLLBARINFO pScrollBarInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if (_WIN32_WINNT >= 0x0501)
+ return (BOOL)::SendMessage(m_hWnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)pScrollBarInfo);
+#else // !(_WIN32_WINNT >= 0x0501)
+ return ::GetScrollBarInfo(m_hWnd, OBJID_CLIENT, pScrollBarInfo);
+#endif // !(_WIN32_WINNT >= 0x0501)
+ }
+#endif // (WINVER >= 0x0500)
+
+// Operations
+ void ShowScrollBar(BOOL bShow = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::ShowScrollBar(m_hWnd, SB_CTL, bShow);
+ }
+
+ BOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::EnableScrollBar(m_hWnd, SB_CTL, nArrowFlags);
+ }
+#endif // !_WIN32_WCE
+};
+
+typedef CScrollBarT<ATL::CWindow> CScrollBar;
+
+
+// --- Windows Common Controls ---
+
+///////////////////////////////////////////////////////////////////////////////
+// CImageList
+
+class CImageList
+{
+public:
+ HIMAGELIST m_hImageList;
+
+// Constructor
+ CImageList(HIMAGELIST hImageList = NULL) : m_hImageList(hImageList)
+ { }
+
+// Operators, etc.
+ CImageList& operator =(HIMAGELIST hImageList)
+ {
+ m_hImageList = hImageList;
+ return *this;
+ }
+
+ operator HIMAGELIST() const { return m_hImageList; }
+
+ void Attach(HIMAGELIST hImageList)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ ATLASSERT(hImageList != NULL);
+ m_hImageList = hImageList;
+ }
+
+ HIMAGELIST Detach()
+ {
+ HIMAGELIST hImageList = m_hImageList;
+ m_hImageList = NULL;
+ return hImageList;
+ }
+
+ bool IsNull() const { return (m_hImageList == NULL); }
+
+// Attributes
+ int GetImageCount() const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetImageCount(m_hImageList);
+ }
+
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetBkColor(m_hImageList);
+ }
+
+ COLORREF SetBkColor(COLORREF cr)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetBkColor(m_hImageList, cr);
+ }
+
+ BOOL GetImageInfo(int nImage, IMAGEINFO* pImageInfo) const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetImageInfo(m_hImageList, nImage, pImageInfo);
+ }
+
+ HICON GetIcon(int nIndex, UINT uFlags = ILD_NORMAL) const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetIcon(m_hImageList, nIndex, uFlags);
+ }
+
+ BOOL GetIconSize(int& cx, int& cy) const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetIconSize(m_hImageList, &cx, &cy);
+ }
+
+ BOOL GetIconSize(SIZE& size) const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_GetIconSize(m_hImageList, (int*)&size.cx, (int*)&size.cy);
+ }
+
+ BOOL SetIconSize(int cx, int cy)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetIconSize(m_hImageList, cx, cy);
+ }
+
+ BOOL SetIconSize(SIZE size)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetIconSize(m_hImageList, size.cx, size.cy);
+ }
+
+ BOOL SetImageCount(UINT uNewCount)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetImageCount(m_hImageList, uNewCount);
+ }
+
+ BOOL SetOverlayImage(int nImage, int nOverlay)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetOverlayImage(m_hImageList, nImage, nOverlay);
+ }
+
+// Operations
+ BOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ m_hImageList = ImageList_Create(cx, cy, nFlags, nInitial, nGrow);
+ return (m_hImageList != NULL) ? TRUE : FALSE;
+ }
+
+ BOOL Create(ATL::_U_STRINGorID bitmap, int cx, int nGrow, COLORREF crMask)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ m_hImageList = ImageList_LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, cx, nGrow, crMask);
+ return (m_hImageList != NULL) ? TRUE : FALSE;
+ }
+
+ BOOL CreateFromImage(ATL::_U_STRINGorID image, int cx, int nGrow, COLORREF crMask, UINT uType, UINT uFlags = LR_DEFAULTCOLOR | LR_DEFAULTSIZE)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ m_hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, cx, nGrow, crMask, uType, uFlags);
+ return (m_hImageList != NULL) ? TRUE : FALSE;
+ }
+
+ BOOL Merge(HIMAGELIST hImageList1, int nImage1, HIMAGELIST hImageList2, int nImage2, int dx, int dy)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ m_hImageList = ImageList_Merge(hImageList1, nImage1, hImageList2, nImage2, dx, dy);
+ return (m_hImageList != NULL) ? TRUE : FALSE;
+ }
+
+#ifndef _WIN32_WCE
+#ifdef __IStream_INTERFACE_DEFINED__
+ BOOL CreateFromStream(LPSTREAM lpStream)
+ {
+ ATLASSERT(m_hImageList == NULL);
+ m_hImageList = ImageList_Read(lpStream);
+ return (m_hImageList != NULL) ? TRUE : FALSE;
+ }
+#endif // __IStream_INTERFACE_DEFINED__
+#endif // !_WIN32_WCE
+
+ BOOL Destroy()
+ {
+ if (m_hImageList == NULL)
+ return FALSE;
+ BOOL bRet = ImageList_Destroy(m_hImageList);
+ if(bRet)
+ m_hImageList = NULL;
+ return bRet;
+ }
+
+ int Add(HBITMAP hBitmap, HBITMAP hBitmapMask = NULL)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_Add(m_hImageList, hBitmap, hBitmapMask);
+ }
+
+ int Add(HBITMAP hBitmap, COLORREF crMask)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_AddMasked(m_hImageList, hBitmap, crMask);
+ }
+
+ BOOL Remove(int nImage)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_Remove(m_hImageList, nImage);
+ }
+
+ BOOL RemoveAll()
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_RemoveAll(m_hImageList);
+ }
+
+ BOOL Replace(int nImage, HBITMAP hBitmap, HBITMAP hBitmapMask)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_Replace(m_hImageList, nImage, hBitmap, hBitmapMask);
+ }
+
+ int AddIcon(HICON hIcon)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_AddIcon(m_hImageList, hIcon);
+ }
+
+ int ReplaceIcon(int nImage, HICON hIcon)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_ReplaceIcon(m_hImageList, nImage, hIcon);
+ }
+
+ HICON ExtractIcon(int nImage)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_ExtractIcon(NULL, m_hImageList, nImage);
+ }
+
+ BOOL Draw(HDC hDC, int nImage, int x, int y, UINT nStyle)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ ATLASSERT(hDC != NULL);
+ return ImageList_Draw(m_hImageList, nImage, hDC, x, y, nStyle);
+ }
+
+ BOOL Draw(HDC hDC, int nImage, POINT pt, UINT nStyle)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ ATLASSERT(hDC != NULL);
+ return ImageList_Draw(m_hImageList, nImage, hDC, pt.x, pt.y, nStyle);
+ }
+
+ BOOL DrawEx(int nImage, HDC hDC, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ ATLASSERT(hDC != NULL);
+ return ImageList_DrawEx(m_hImageList, nImage, hDC, x, y, dx, dy, rgbBk, rgbFg, fStyle);
+ }
+
+ BOOL DrawEx(int nImage, HDC hDC, RECT& rect, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ ATLASSERT(hDC != NULL);
+ return ImageList_DrawEx(m_hImageList, nImage, hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rgbBk, rgbFg, fStyle);
+ }
+
+ static BOOL DrawIndirect(IMAGELISTDRAWPARAMS* pimldp)
+ {
+ return ImageList_DrawIndirect(pimldp);
+ }
+
+ BOOL Copy(int nSrc, int nDst, UINT uFlags = ILCF_MOVE)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_Copy(m_hImageList, nDst, m_hImageList, nSrc, uFlags);
+ }
+
+#ifdef __IStream_INTERFACE_DEFINED__
+#ifndef _WIN32_WCE
+ static HIMAGELIST Read(LPSTREAM lpStream)
+ {
+ return ImageList_Read(lpStream);
+ }
+
+ BOOL Write(LPSTREAM lpStream)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_Write(m_hImageList, lpStream);
+ }
+#endif // !_WIN32_WCE
+
+#if (_WIN32_WINNT >= 0x0501)
+ static HRESULT ReadEx(DWORD dwFlags, LPSTREAM lpStream, REFIID riid, PVOID* ppv)
+ {
+ return ImageList_ReadEx(dwFlags, lpStream, riid, ppv);
+ }
+
+ HRESULT WriteEx(DWORD dwFlags, LPSTREAM lpStream)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_WriteEx(m_hImageList, dwFlags, lpStream);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+#endif // __IStream_INTERFACE_DEFINED__
+
+ // Drag operations
+ BOOL BeginDrag(int nImage, POINT ptHotSpot)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_BeginDrag(m_hImageList, nImage, ptHotSpot.x, ptHotSpot.y);
+ }
+
+ BOOL BeginDrag(int nImage, int xHotSpot, int yHotSpot)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_BeginDrag(m_hImageList, nImage, xHotSpot, yHotSpot);
+ }
+
+ static void EndDrag()
+ {
+ ImageList_EndDrag();
+ }
+
+ static BOOL DragMove(POINT pt)
+ {
+ return ImageList_DragMove(pt.x, pt.y);
+ }
+
+ static BOOL DragMove(int x, int y)
+ {
+ return ImageList_DragMove(x, y);
+ }
+
+ BOOL SetDragCursorImage(int nDrag, POINT ptHotSpot)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetDragCursorImage(m_hImageList, nDrag, ptHotSpot.x, ptHotSpot.y);
+ }
+
+ BOOL SetDragCursorImage(int nDrag, int xHotSpot, int yHotSpot)
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return ImageList_SetDragCursorImage(m_hImageList, nDrag, xHotSpot, yHotSpot);
+ }
+
+ static BOOL DragShowNolock(BOOL bShow = TRUE)
+ {
+ return ImageList_DragShowNolock(bShow);
+ }
+
+ static CImageList GetDragImage(LPPOINT lpPoint, LPPOINT lpPointHotSpot)
+ {
+ return CImageList(ImageList_GetDragImage(lpPoint, lpPointHotSpot));
+ }
+
+ static BOOL DragEnter(HWND hWnd, POINT point)
+ {
+ return ImageList_DragEnter(hWnd, point.x, point.y);
+ }
+
+ static BOOL DragEnter(HWND hWnd, int x, int y)
+ {
+ return ImageList_DragEnter(hWnd, x, y);
+ }
+
+ static BOOL DragLeave(HWND hWnd)
+ {
+ return ImageList_DragLeave(hWnd);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ CImageList Duplicate() const
+ {
+ ATLASSERT(m_hImageList != NULL);
+ return CImageList(ImageList_Duplicate(m_hImageList));
+ }
+
+ static CImageList Duplicate(HIMAGELIST hImageList)
+ {
+ ATLASSERT(hImageList != NULL);
+ return CImageList(ImageList_Duplicate(hImageList));
+ }
+#endif // (_WIN32_IE >= 0x0400)
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CToolTipCtrl
+
+#ifndef _WIN32_WCE
+
+class CToolInfo : public TOOLINFO
+{
+public:
+ CToolInfo(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL)
+ {
+ Init(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam);
+ }
+
+ operator LPTOOLINFO() { return this; }
+
+ operator LPARAM() { return (LPARAM)this; }
+
+ void Init(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL)
+ {
+ ATLASSERT(::IsWindow(hWnd));
+ memset(this, 0, sizeof(TOOLINFO));
+ cbSize = sizeof(TOOLINFO);
+ uFlags = nFlags;
+ if(nIDTool == 0)
+ {
+ hwnd = ::GetParent(hWnd);
+ uFlags |= TTF_IDISHWND;
+ uId = (UINT_PTR)hWnd;
+ }
+ else
+ {
+ hwnd = hWnd;
+ uId = nIDTool;
+ }
+ if(lpRect != NULL)
+ rect = *lpRect;
+ hinst = ModuleHelper::GetResourceInstance();
+ lpszText = lpstrText;
+ lParam = lUserParam;
+ }
+};
+
+template <class TBase>
+class CToolTipCtrlT : public TBase
+{
+public:
+// Constructors
+ CToolTipCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CToolTipCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return TOOLTIPS_CLASS;
+ }
+
+ void GetText(LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&lpToolInfo);
+ }
+
+ void GetText(LPTSTR lpstrText, HWND hWnd, UINT nIDTool = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+ CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText);
+ ::SendMessage(m_hWnd, TTM_GETTEXT, 0, ti);
+ }
+
+ BOOL GetToolInfo(LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo);
+ }
+
+ BOOL GetToolInfo(HWND hWnd, UINT nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+ ATLASSERT(puFlags != NULL);
+ ATLASSERT(lpRect != NULL);
+ CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText);
+ BOOL bRet = (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, ti);
+ if(bRet != FALSE)
+ {
+ *puFlags = ti.uFlags;
+ *lpRect = ti.rect;
+ }
+ return bRet;
+ }
+
+ void SetToolInfo(LPTOOLINFO lpToolInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo);
+ }
+
+ void SetToolRect(LPTOOLINFO lpToolInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo);
+ }
+
+ void SetToolRect(HWND hWnd, UINT nIDTool, LPCRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+ ATLASSERT(nIDTool != 0);
+
+ CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, NULL);
+ ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, ti);
+ }
+
+ int GetToolCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TTM_GETTOOLCOUNT, 0, 0L);
+ }
+
+ int GetDelayTime(DWORD dwType) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TTM_GETDELAYTIME, dwType, 0L);
+ }
+
+ void SetDelayTime(DWORD dwType, int nTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0));
+ }
+
+ void GetMargin(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_GETMARGIN, 0, (LPARAM)lpRect);
+ }
+
+ void SetMargin(LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)lpRect);
+ }
+
+ int GetMaxTipWidth() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TTM_GETMAXTIPWIDTH, 0, 0L);
+ }
+
+ int SetMaxTipWidth(int nWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, nWidth);
+ }
+
+ COLORREF GetTipBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPBKCOLOR, 0, 0L);
+ }
+
+ void SetTipBkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L);
+ }
+
+ COLORREF GetTipTextColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPTEXTCOLOR, 0, 0L);
+ }
+
+ void SetTipTextColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L);
+ }
+
+ BOOL GetCurrentTool(LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo);
+ }
+
+#if (_WIN32_IE >= 0x0500)
+ SIZE GetBubbleSize(LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo);
+ SIZE size = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) };
+ return size;
+ }
+
+ BOOL SetTitle(UINT uIcon, LPCTSTR lpstrTitle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle);
+ }
+#endif // (_WIN32_IE >= 0x0500)
+
+#if (_WIN32_WINNT >= 0x0501)
+ void GetTitle(PTTGETTITLE pTTGetTitle) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_GETTITLE, 0, (LPARAM)pTTGetTitle);
+ }
+
+ void SetWindowTheme(LPCWSTR lpstrTheme)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+// Operations
+ void Activate(BOOL bActivate)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L);
+ }
+
+ BOOL AddTool(LPTOOLINFO lpToolInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)lpToolInfo);
+ }
+
+ BOOL AddTool(HWND hWnd, ATL::_U_STRINGorID text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT nIDTool = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+ // the toolrect and toolid must both be zero or both valid
+ ATLASSERT((lpRectTool != NULL && nIDTool != 0) || (lpRectTool == NULL && nIDTool == 0));
+
+ CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text.m_lpstr);
+ return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, ti);
+ }
+
+ void DelTool(LPTOOLINFO lpToolInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)lpToolInfo);
+ }
+
+ void DelTool(HWND hWnd, UINT nIDTool = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+
+ CToolInfo ti(0, hWnd, nIDTool, NULL, NULL);
+ ::SendMessage(m_hWnd, TTM_DELTOOL, 0, ti);
+ }
+
+ BOOL HitTest(LPTTHITTESTINFO lpHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)lpHitTestInfo);
+ }
+
+ BOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+ ATLASSERT(lpToolInfo != NULL);
+
+ TTHITTESTINFO hti = { 0 };
+ hti.ti.cbSize = sizeof(TOOLINFO);
+ hti.hwnd = hWnd;
+ hti.pt.x = pt.x;
+ hti.pt.y = pt.y;
+ if((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti) != FALSE)
+ {
+ *lpToolInfo = hti.ti;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ void RelayEvent(LPMSG lpMsg)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_RELAYEVENT, 0, (LPARAM)lpMsg);
+ }
+
+ void UpdateTipText(LPTOOLINFO lpToolInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo);
+ }
+
+ void UpdateTipText(ATL::_U_STRINGorID text, HWND hWnd, UINT nIDTool = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hWnd != NULL);
+
+ CToolInfo ti(0, hWnd, nIDTool, NULL, (LPTSTR)text.m_lpstr);
+ ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, ti);
+ }
+
+ BOOL EnumTools(UINT nTool, LPTOOLINFO lpToolInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo);
+ }
+
+ void Pop()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_POP, 0, 0L);
+ }
+
+ void TrackActivate(LPTOOLINFO lpToolInfo, BOOL bActivate)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, (LPARAM)lpToolInfo);
+ }
+
+ void TrackPosition(int xPos, int yPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos));
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ void Update()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_UPDATE, 0, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500)
+ BOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect);
+ }
+#endif // (_WIN32_IE >= 0x0500)
+
+#if (_WIN32_WINNT >= 0x0501)
+ void Popup()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TTM_POPUP, 0, 0L);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+};
+
+typedef CToolTipCtrlT<ATL::CWindow> CToolTipCtrl;
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CHeaderCtrl
+
+template <class TBase>
+class CHeaderCtrlT : public TBase
+{
+public:
+// Constructors
+ CHeaderCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CHeaderCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_HEADER;
+ }
+
+ int GetItemCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_GETITEMCOUNT, 0, 0L);
+ }
+
+ BOOL GetItem(int nIndex, LPHDITEM pHeaderItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETITEM, nIndex, (LPARAM)pHeaderItem);
+ }
+
+ BOOL SetItem(int nIndex, LPHDITEM pHeaderItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_SETITEM, nIndex, (LPARAM)pHeaderItem);
+ }
+
+ CImageList GetImageList() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_GETIMAGELIST, 0, 0L));
+ }
+
+ CImageList SetImageList(HIMAGELIST hImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_SETIMAGELIST, 0, (LPARAM)hImageList));
+ }
+
+ BOOL GetOrderArray(int nSize, int* lpnArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETORDERARRAY, nSize, (LPARAM)lpnArray);
+ }
+
+ BOOL SetOrderArray(int nSize, int* lpnArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_SETORDERARRAY, nSize, (LPARAM)lpnArray);
+ }
+
+ BOOL GetItemRect(int nIndex, LPRECT lpItemRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMRECT, nIndex, (LPARAM)lpItemRect);
+ }
+
+ int SetHotDivider(BOOL bPos, DWORD dwInputValue)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_SETHOTDIVIDER, bPos, dwInputValue);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ int GetBitmapMargin() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_GETBITMAPMARGIN, 0, 0L);
+ }
+
+ int SetBitmapMargin(int nWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_SETBITMAPMARGIN, nWidth, 0L);
+ }
+
+ int SetFilterChangeTimeout(DWORD dwTimeOut)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, dwTimeOut);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0600)
+ BOOL GetItemDropDownRect(int nIndex, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect);
+ }
+
+ BOOL GetOverflowRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_GETOVERFLOWRECT, 0, (LPARAM)lpRect);
+ }
+
+ int GetFocusedItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_GETFOCUSEDITEM, 0, 0L);
+ }
+
+ BOOL SetFocusedItem(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_SETFOCUSEDITEM, 0, nIndex);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ int InsertItem(int nIndex, LPHDITEM phdi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_INSERTITEM, nIndex, (LPARAM)phdi);
+ }
+
+ int AddItem(LPHDITEM phdi)
+ {
+ return InsertItem(GetItemCount(), phdi);
+ }
+
+ BOOL DeleteItem(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_DELETEITEM, nIndex, 0L);
+ }
+
+ BOOL Layout(HD_LAYOUT* pHeaderLayout)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, HDM_LAYOUT, 0, (LPARAM)pHeaderLayout);
+ }
+
+ int HitTest(LPHDHITTESTINFO lpHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)lpHitTestInfo);
+ }
+
+ int OrderToIndex(int nOrder)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_ORDERTOINDEX, nOrder, 0L);
+ }
+
+ CImageList CreateDragImage(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_CREATEDRAGIMAGE, nIndex, 0L));
+ }
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ int EditFilter(int nColumn, BOOL bDiscardChanges)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_EDITFILTER, nColumn, MAKELPARAM(bDiscardChanges, 0));
+ }
+
+ int ClearFilter(int nColumn)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, nColumn, 0L);
+ }
+
+ int ClearAllFilters()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, (WPARAM)-1, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+};
+
+typedef CHeaderCtrlT<ATL::CWindow> CHeaderCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CListViewCtrl
+
+template <class TBase>
+class CListViewCtrlT : public TBase
+{
+public:
+// Constructors
+ CListViewCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CListViewCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_LISTVIEW;
+ }
+
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_GETBKCOLOR, 0, 0L);
+ }
+
+ BOOL SetBkColor(COLORREF cr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETBKCOLOR, 0, cr);
+ }
+
+ CImageList GetImageList(int nImageListType) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, nImageListType, 0L));
+ }
+
+ CImageList SetImageList(HIMAGELIST hImageList, int nImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, nImageList, (LPARAM)hImageList));
+ }
+
+ int GetItemCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0L);
+ }
+
+ BOOL SetItemCount(int nItems)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, 0L);
+ }
+
+ BOOL GetItem(LPLVITEM pItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem);
+ }
+
+ BOOL SetItem(const LVITEM* pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)pItem);
+ }
+
+ BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem,
+ int nImage, UINT nState, UINT nStateMask, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.mask = nMask;
+ lvi.iItem = nItem;
+ lvi.iSubItem = nSubItem;
+ lvi.stateMask = nStateMask;
+ lvi.state = nState;
+ lvi.pszText = (LPTSTR) lpszItem;
+ lvi.iImage = nImage;
+ lvi.lParam = lParam;
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi);
+ }
+
+ UINT GetItemState(int nItem, UINT nMask) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, LVM_GETITEMSTATE, nItem, nMask);
+ }
+
+ BOOL SetItemState(int nItem, UINT nState, UINT nStateMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.state = nState;
+ lvi.stateMask = nStateMask;
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi);
+ }
+
+ BOOL SetItemState(int nItem, LPLVITEM pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)pItem);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+ LVITEM lvi = { 0 };
+ lvi.iSubItem = nSubItem;
+
+ LPTSTR lpstrText = NULL;
+ int nRes = 0;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrText = new TCHAR[nLen]);
+ if(lpstrText == NULL)
+ break;
+ lpstrText[0] = NULL;
+ lvi.cchTextMax = nLen;
+ lvi.pszText = lpstrText;
+ nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);
+ if(nRes < nLen - 1)
+ break;
+ delete [] lpstrText;
+ lpstrText = NULL;
+ }
+
+ if(lpstrText != NULL)
+ {
+ if(nRes != 0)
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ delete [] lpstrText;
+ }
+
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetItemText(int nItem, int nSubItem, _CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.iSubItem = nSubItem;
+
+ strText.Empty();
+ int nRes = 0;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ lvi.cchTextMax = nLen;
+ lvi.pszText = strText.GetBufferSetLength(nLen);
+ if(lvi.pszText == NULL)
+ {
+ nRes = 0;
+ break;
+ }
+ nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);
+ if(nRes < nLen - 1)
+ break;
+ }
+ strText.ReleaseBuffer();
+ return nRes;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ int GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.iSubItem = nSubItem;
+ lvi.cchTextMax = nLen;
+ lvi.pszText = lpszText;
+ return (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);
+ }
+
+ BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(nItem, nSubItem, LVIF_TEXT, lpszText, 0, 0, 0, 0);
+ }
+
+ DWORD_PTR GetItemData(int nItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.iItem = nItem;
+ lvi.mask = LVIF_PARAM;
+ BOOL bRet = (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi);
+ return (DWORD_PTR)(bRet ? lvi.lParam : NULL);
+ }
+
+ BOOL SetItemData(int nItem, DWORD_PTR dwData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(nItem, 0, LVIF_PARAM, NULL, 0, 0, 0, (LPARAM)dwData);
+ }
+
+ UINT GetCallbackMask() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, LVM_GETCALLBACKMASK, 0, 0L);
+ }
+
+ BOOL SetCallbackMask(UINT nMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETCALLBACKMASK, nMask, 0L);
+ }
+
+ BOOL GetItemPosition(int nItem, LPPOINT lpPoint) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)lpPoint);
+ }
+
+ BOOL SetItemPosition(int nItem, POINT pt)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt);
+ }
+
+ BOOL SetItemPosition(int nItem, int x, int y)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON));
+ POINT pt = { x, y };
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt);
+ }
+
+ int GetStringWidth(LPCTSTR lpsz) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETSTRINGWIDTH, 0, (LPARAM)lpsz);
+ }
+
+ CEdit GetEditControl() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CEdit((HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L));
+ }
+
+ BOOL GetColumn(int nCol, LVCOLUMN* pColumn) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMN, nCol, (LPARAM)pColumn);
+ }
+
+ BOOL SetColumn(int nCol, const LVCOLUMN* pColumn)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMN, nCol, (LPARAM)pColumn);
+ }
+
+ int GetColumnWidth(int nCol) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETCOLUMNWIDTH, nCol, 0L);
+ }
+
+ BOOL SetColumnWidth(int nCol, int cx)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNWIDTH, nCol, MAKELPARAM(cx, 0));
+ }
+
+ BOOL GetViewRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETVIEWRECT, 0, (LPARAM)lpRect);
+ }
+
+ COLORREF GetTextColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTCOLOR, 0, 0L);
+ }
+
+ BOOL SetTextColor(COLORREF cr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTCOLOR, 0, cr);
+ }
+
+ COLORREF GetTextBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTBKCOLOR, 0, 0L);
+ }
+
+ BOOL SetTextBkColor(COLORREF cr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTBKCOLOR, 0, cr);
+ }
+
+ int GetTopIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0L);
+ }
+
+ int GetCountPerPage() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETCOUNTPERPAGE, 0, 0L);
+ }
+
+ BOOL GetOrigin(LPPOINT lpPoint) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETORIGIN, 0, (LPARAM)lpPoint);
+ }
+
+ UINT GetSelectedCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, LVM_GETSELECTEDCOUNT, 0, 0L);
+ }
+
+ BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ lpRect->left = nCode;
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)lpRect);
+ }
+
+#ifndef _WIN32_WCE
+ HCURSOR GetHotCursor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HCURSOR)::SendMessage(m_hWnd, LVM_GETHOTCURSOR, 0, 0L);
+ }
+
+ HCURSOR SetHotCursor(HCURSOR hHotCursor)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HCURSOR)::SendMessage(m_hWnd, LVM_SETHOTCURSOR, 0, (LPARAM)hHotCursor);
+ }
+
+ int GetHotItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETHOTITEM, 0, 0L);
+ }
+
+ int SetHotItem(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SETHOTITEM, nIndex, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL GetColumnOrderArray(int nCount, int* lpnArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray);
+ }
+
+ BOOL SetColumnOrderArray(int nCount, int* lpnArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray);
+ }
+
+ CHeaderCtrl GetHeader() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CHeaderCtrl((HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0L));
+ }
+
+ BOOL GetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT);
+ ATLASSERT(lpRect != NULL);
+ lpRect->top = nSubItem;
+ lpRect->left = nFlag;
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, nItem, (LPARAM)lpRect);
+ }
+
+ DWORD SetIconSpacing(int cx, int cy)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_ICON);
+ return (DWORD)::SendMessage(m_hWnd, LVM_SETICONSPACING, 0, MAKELPARAM(cx, cy));
+ }
+
+ int GetISearchString(LPTSTR lpstr) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETISEARCHSTRING, 0, (LPARAM)lpstr);
+ }
+
+ void GetItemSpacing(SIZE& sizeSpacing, BOOL bSmallIconView = FALSE) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, LVM_GETITEMSPACING, bSmallIconView, 0L);
+ sizeSpacing.cx = GET_X_LPARAM(dwRet);
+ sizeSpacing.cy = GET_Y_LPARAM(dwRet);
+ }
+
+#if (_WIN32_WCE >= 410)
+ void SetItemSpacing(INT cySpacing)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ListView_SetItemSpacing(m_hWnd, cySpacing);
+ }
+#endif // (_WIN32_WCE >= 410)
+
+ // single-selection only
+ int GetSelectedIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0);
+ return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0));
+ }
+
+ BOOL GetSelectedItem(LPLVITEM pItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0);
+ ATLASSERT(pItem != NULL);
+ pItem->iItem = (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0));
+ if(pItem->iItem == -1)
+ return FALSE;
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem);
+ }
+
+ // extended list view styles
+ DWORD GetExtendedListViewStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0L);
+ }
+
+ // dwExMask = 0 means all styles
+ DWORD SetExtendedListViewStyle(DWORD dwExStyle, DWORD dwExMask = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExMask, dwExStyle);
+ }
+
+ // checkboxes only
+ BOOL GetCheckState(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetExtendedListViewStyle() & LVS_EX_CHECKBOXES) != 0);
+ UINT uRet = GetItemState(nIndex, LVIS_STATEIMAGEMASK);
+ return (uRet >> 12) - 1;
+ }
+
+ BOOL SetCheckState(int nItem, BOOL bCheck)
+ {
+ int nCheck = bCheck ? 2 : 1; // one based index
+ return SetItemState(nItem, INDEXTOSTATEIMAGEMASK(nCheck), LVIS_STATEIMAGEMASK);
+ }
+
+ // view type
+ DWORD GetViewType() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (GetStyle() & LVS_TYPEMASK);
+ }
+
+ DWORD SetViewType(DWORD dwType)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(dwType == LVS_ICON || dwType == LVS_SMALLICON || dwType == LVS_LIST || dwType == LVS_REPORT);
+ DWORD dwOldType = GetViewType();
+ if(dwType != dwOldType)
+ ModifyStyle(LVS_TYPEMASK, (dwType & LVS_TYPEMASK));
+ return dwOldType;
+ }
+
+#if (_WIN32_IE >= 0x0400)
+#ifndef _WIN32_WCE
+ BOOL GetBkImage(LPLVBKIMAGE plvbki) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETBKIMAGE, 0, (LPARAM)plvbki);
+ }
+
+ BOOL SetBkImage(LPLVBKIMAGE plvbki)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETBKIMAGE, 0, (LPARAM)plvbki);
+ }
+#endif // !_WIN32_WCE
+
+ int GetSelectionMark() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETSELECTIONMARK, 0, 0L);
+ }
+
+ int SetSelectionMark(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SETSELECTIONMARK, 0, nIndex);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetWorkAreas(int nWorkAreas, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETWORKAREAS, nWorkAreas, (LPARAM)lpRect);
+ }
+
+ BOOL SetWorkAreas(int nWorkAreas, LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETWORKAREAS, nWorkAreas, (LPARAM)lpRect);
+ }
+
+ DWORD GetHoverTime() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0);
+ return (DWORD)::SendMessage(m_hWnd, LVM_GETHOVERTIME, 0, 0L);
+ }
+
+ DWORD SetHoverTime(DWORD dwHoverTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0);
+ return (DWORD)::SendMessage(m_hWnd, LVM_SETHOVERTIME, 0, dwHoverTime);
+ }
+
+ BOOL GetNumberOfWorkAreas(int* pnWorkAreas) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETNUMBEROFWORKAREAS, 0, (LPARAM)pnWorkAreas);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL SetItemCountEx(int nItems, DWORD dwFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(((GetStyle() & LVS_OWNERDATA) != 0) && (((GetStyle() & LVS_TYPEMASK) == LVS_REPORT) || ((GetStyle() & LVS_TYPEMASK) == LVS_LIST)));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, dwFlags);
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetToolTips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L));
+ }
+
+ CToolTipCtrl SetToolTips(HWND hWndTT)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L));
+ }
+
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_WINNT >= 0x0501)
+ int GetSelectedColumn() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETSELECTEDCOLUMN, 0, 0L);
+ }
+
+ void SetSelectedColumn(int nColumn)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_SETSELECTEDCOLUMN, nColumn, 0L);
+ }
+
+ DWORD GetView() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, LVM_GETVIEW, 0, 0L);
+ }
+
+ int SetView(DWORD dwView)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SETVIEW, dwView, 0L);
+ }
+
+ BOOL IsGroupViewEnabled() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_ISGROUPVIEWENABLED, 0, 0L);
+ }
+
+ int GetGroupInfo(int nGroupID, PLVGROUP pGroup) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETGROUPINFO, nGroupID, (LPARAM)pGroup);
+ }
+
+ int SetGroupInfo(int nGroupID, PLVGROUP pGroup)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SETGROUPINFO, nGroupID, (LPARAM)pGroup);
+ }
+
+ void GetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_GETGROUPMETRICS, 0, (LPARAM)pGroupMetrics);
+ }
+
+ void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_SETGROUPMETRICS, 0, (LPARAM)pGroupMetrics);
+ }
+
+ void GetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_GETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo);
+ }
+
+ BOOL SetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo);
+ }
+
+ void GetTileInfo(PLVTILEINFO pTileInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_GETTILEINFO, 0, (LPARAM)pTileInfo);
+ }
+
+ BOOL SetTileInfo(PLVTILEINFO pTileInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEINFO, 0, (LPARAM)pTileInfo);
+ }
+
+ BOOL GetInsertMark(LPLVINSERTMARK pInsertMark) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETINSERTMARK, 0, (LPARAM)pInsertMark);
+ }
+
+ BOOL SetInsertMark(LPLVINSERTMARK pInsertMark)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETINSERTMARK, 0, (LPARAM)pInsertMark);
+ }
+
+ int GetInsertMarkRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETINSERTMARKRECT, 0, (LPARAM)lpRect);
+ }
+
+ COLORREF GetInsertMarkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_GETINSERTMARKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetInsertMarkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_SETINSERTMARKCOLOR, 0, clr);
+ }
+
+ COLORREF GetOutlineColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_GETOUTLINECOLOR, 0, 0L);
+ }
+
+ COLORREF SetOutlineColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, LVM_SETOUTLINECOLOR, 0, clr);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+ int GetGroupCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETGROUPCOUNT, 0, 0L);
+ }
+
+ BOOL GetGroupInfoByIndex(int nIndex, PLVGROUP pGroup) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPINFOBYINDEX, nIndex, (LPARAM)pGroup);
+ }
+
+ BOOL GetGroupRect(int nGroupID, int nType, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpRect != NULL);
+ if(lpRect != NULL)
+ lpRect->top = nType;
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPRECT, nGroupID, (LPARAM)lpRect);
+ }
+
+ UINT GetGroupState(int nGroupID, UINT uMask) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, LVM_GETGROUPSTATE, nGroupID, (LPARAM)uMask);
+ }
+
+ int GetFocusedGroup() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETFOCUSEDGROUP, 0, 0L);
+ }
+
+ BOOL GetEmptyText(LPWSTR lpstrText, int cchText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETEMPTYTEXT, cchText, (LPARAM)lpstrText);
+ }
+
+ BOOL GetFooterRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERRECT, 0, (LPARAM)lpRect);
+ }
+
+ BOOL GetFooterInfo(LPLVFOOTERINFO lpFooterInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERINFO, 0, (LPARAM)lpFooterInfo);
+ }
+
+ BOOL GetFooterItemRect(int nItem, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEMRECT, nItem, (LPARAM)lpRect);
+ }
+
+ BOOL GetFooterItem(int nItem, LPLVFOOTERITEM lpFooterItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEM, nItem, (LPARAM)lpFooterItem);
+ }
+
+ BOOL GetItemIndexRect(PLVITEMINDEX pItemIndex, int nSubItem, int nType, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pItemIndex != NULL);
+ ATLASSERT(lpRect != NULL);
+ if(lpRect != NULL)
+ {
+ lpRect->top = nSubItem;
+ lpRect->left = nType;
+ }
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMINDEXRECT, (WPARAM)pItemIndex, (LPARAM)lpRect);
+ }
+
+ BOOL SetItemIndexState(PLVITEMINDEX pItemIndex, UINT uState, UINT dwMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvi = { 0 };
+ lvi.state = uState;
+ lvi.stateMask = dwMask;
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMINDEXSTATE, (WPARAM)pItemIndex, (LPARAM)&lvi);
+ }
+
+ BOOL GetNextItemIndex(PLVITEMINDEX pItemIndex, WORD wFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_GETNEXTITEMINDEX, (WPARAM)pItemIndex, MAKELPARAM(wFlags, 0));
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ int InsertColumn(int nCol, const LVCOLUMN* pColumn)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn);
+ }
+
+ int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT,
+ int nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1)
+ {
+ LVCOLUMN column = { 0 };
+ column.mask = LVCF_TEXT|LVCF_FMT;
+ column.pszText = (LPTSTR)lpszColumnHeading;
+ column.fmt = nFormat;
+ if (nWidth != -1)
+ {
+ column.mask |= LVCF_WIDTH;
+ column.cx = nWidth;
+ }
+ if (nSubItem != -1)
+ {
+ column.mask |= LVCF_SUBITEM;
+ column.iSubItem = nSubItem;
+ }
+ if (iImage != -1)
+ {
+ column.mask |= LVCF_IMAGE;
+ column.iImage = iImage;
+ }
+ if (iOrder != -1)
+ {
+ column.mask |= LVCF_ORDER;
+ column.iOrder = iOrder;
+ }
+ return InsertColumn(nCol, &column);
+ }
+
+ BOOL DeleteColumn(int nCol)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_DELETECOLUMN, nCol, 0L);
+ }
+
+ int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM item = { 0 };
+ item.mask = nMask;
+ item.iItem = nItem;
+ item.iSubItem = 0;
+ item.pszText = (LPTSTR)lpszItem;
+ item.state = nState;
+ item.stateMask = nStateMask;
+ item.iImage = nImage;
+ item.lParam = lParam;
+ return InsertItem(&item);
+ }
+
+ int InsertItem(const LVITEM* pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem);
+ }
+
+ int InsertItem(int nItem, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0);
+ }
+
+ int InsertItem(int nItem, LPCTSTR lpszItem, int nImage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0);
+ }
+
+ int GetNextItem(int nItem, int nFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0));
+ }
+
+ BOOL DeleteItem(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_DELETEITEM, nItem, 0L);
+ }
+
+ BOOL DeleteAllItems()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_DELETEALLITEMS, 0, 0L);
+ }
+
+ int FindItem(LVFINDINFO* pFindInfo, int nStart) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo);
+ }
+
+ int HitTest(LVHITTESTINFO* pHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo);
+ }
+
+ int HitTest(POINT pt, UINT* pFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVHITTESTINFO hti = { 0 };
+ hti.pt = pt;
+ int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti);
+ if (pFlags != NULL)
+ *pFlags = hti.flags;
+ return nRes;
+ }
+
+ BOOL EnsureVisible(int nItem, BOOL bPartialOK)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_ENSUREVISIBLE, nItem, MAKELPARAM(bPartialOK, 0));
+ }
+
+ BOOL Scroll(SIZE size)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SCROLL, size.cx, size.cy);
+ }
+
+ BOOL RedrawItems(int nFirst, int nLast)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_REDRAWITEMS, nFirst, nLast);
+ }
+
+ BOOL Arrange(UINT nCode)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_ARRANGE, nCode, 0L);
+ }
+
+ CEdit EditLabel(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CEdit((HWND)::SendMessage(m_hWnd, LVM_EDITLABEL, nItem, 0L));
+ }
+
+ BOOL Update(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_UPDATE, nItem, 0L);
+ }
+
+ BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMS, (WPARAM)lParamSort, (LPARAM)pfnCompare);
+ }
+
+ CImageList RemoveImageList(int nImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, (WPARAM)nImageList, NULL));
+ }
+
+ CImageList CreateDragImage(int nItem, LPPOINT lpPoint)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint));
+ }
+
+ DWORD ApproximateViewRect(int cx = -1, int cy = -1, int nCount = -1)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, LVM_APPROXIMATEVIEWRECT, nCount, MAKELPARAM(cx, cy));
+ }
+
+ int SubItemHitTest(LPLVHITTESTINFO lpInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, (LPARAM)lpInfo);
+ }
+
+ int AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1,
+ int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
+ int nFmt = LVCFMT_LEFT)
+ {
+ const int cxOffset = 15;
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVCOLUMN lvc = { 0 };
+ lvc.mask = nMask;
+ lvc.fmt = nFmt;
+ lvc.pszText = (LPTSTR)strItem;
+ lvc.cx = GetStringWidth(lvc.pszText) + cxOffset;
+ if(nMask & LVCF_SUBITEM)
+ lvc.iSubItem = (nSubItem != -1) ? nSubItem : nItem;
+ return InsertColumn(nItem, &lvc);
+ }
+
+ int AddItem(int nItem, int nSubItem, LPCTSTR strItem, int nImageIndex = -1)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVITEM lvItem = { 0 };
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iItem = nItem;
+ lvItem.iSubItem = nSubItem;
+ lvItem.pszText = (LPTSTR)strItem;
+ if(nImageIndex != -1)
+ {
+ lvItem.mask |= LVIF_IMAGE;
+ lvItem.iImage = nImageIndex;
+ }
+ if(nSubItem == 0)
+ return InsertItem(&lvItem);
+ return SetItem(&lvItem) ? nItem : -1;
+ }
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMSEX, (WPARAM)lParamSort, (LPARAM)pfnCompare);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501)
+ int InsertGroup(int nItem, PLVGROUP pGroup)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_INSERTGROUP, nItem, (LPARAM)pGroup);
+ }
+
+ int AddGroup(PLVGROUP pGroup)
+ {
+ return InsertGroup(-1, pGroup);
+ }
+
+ int RemoveGroup(int nGroupID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_REMOVEGROUP, nGroupID, 0L);
+ }
+
+ void MoveGroup(int nGroupID, int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_MOVEGROUP, nGroupID, nItem);
+ }
+
+ void MoveItemToGroup(int nItem, int nGroupID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_MOVEITEMTOGROUP, nItem, nGroupID);
+ }
+
+ int EnableGroupView(BOOL bEnable)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_ENABLEGROUPVIEW, bEnable, 0L);
+ }
+
+ int SortGroups(PFNLVGROUPCOMPARE pCompareFunc, LPVOID lpVoid = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SORTGROUPS, (WPARAM)pCompareFunc, (LPARAM)lpVoid);
+ }
+
+ void InsertGroupSorted(PLVINSERTGROUPSORTED pInsertGroupSorted)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_INSERTGROUPSORTED, (WPARAM)pInsertGroupSorted, 0L);
+ }
+
+ void RemoveAllGroups()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_REMOVEALLGROUPS, 0, 0L);
+ }
+
+ BOOL HasGroup(int nGroupID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_HASGROUP, nGroupID, 0L);
+ }
+
+ BOOL InsertMarkHitTest(LPPOINT lpPoint, LPLVINSERTMARK pInsertMark) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)pInsertMark);
+ }
+
+ BOOL SetInfoTip(PLVSETINFOTIP pSetInfoTip)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LVM_SETINFOTIP, 0, (LPARAM)pSetInfoTip);
+ }
+
+ void CancelEditLabel()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, LVM_CANCELEDITLABEL, 0, 0L);
+ }
+
+ UINT MapIndexToID(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, LVM_MAPINDEXTOID, nIndex, 0L);
+ }
+
+ int MapIDToIndex(UINT uID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_MAPIDTOINDEX, uID, 0L);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+ int HitTestEx(LPLVHITTESTINFO lpHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo);
+ }
+
+ int HitTestEx(POINT pt, UINT* pFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LVHITTESTINFO hti = { 0 };
+ hti.pt = pt;
+ int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)&hti);
+ if (pFlags != NULL)
+ *pFlags = hti.flags;
+ return nRes;
+ }
+
+ int SubItemHitTestEx(LPLVHITTESTINFO lpHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+ // Note: selects only one item
+ BOOL SelectItem(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ // multi-selection only: de-select all items
+ if((GetStyle() & LVS_SINGLESEL) == 0)
+ SetItemState(-1, 0, LVIS_SELECTED);
+
+ BOOL bRet = SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ if(bRet)
+ bRet = EnsureVisible(nIndex, FALSE);
+
+ return bRet;
+ }
+};
+
+typedef CListViewCtrlT<ATL::CWindow> CListViewCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTreeViewCtrl
+
+template <class TBase>
+class CTreeViewCtrlT : public TBase
+{
+public:
+// Constructors
+ CTreeViewCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CTreeViewCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_TREEVIEW;
+ }
+
+ UINT GetCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TVM_GETCOUNT, 0, 0L);
+ }
+
+ UINT GetIndent() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TVM_GETINDENT, 0, 0L);
+ }
+
+ void SetIndent(UINT nIndent)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TVM_SETINDENT, nIndent, 0L);
+ }
+
+ CImageList GetImageList(int nImageListType = TVSIL_NORMAL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_GETIMAGELIST, (WPARAM)nImageListType, 0L));
+ }
+
+ CImageList SetImageList(HIMAGELIST hImageList, int nImageListType = TVSIL_NORMAL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageListType, (LPARAM)hImageList));
+ }
+
+ BOOL GetItem(LPTVITEM pItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem);
+ }
+
+ BOOL SetItem(LPTVITEM pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem);
+ }
+
+ BOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = nMask;
+ item.pszText = (LPTSTR) lpszItem;
+ item.iImage = nImage;
+ item.iSelectedImage = nSelectedImage;
+ item.state = nState;
+ item.stateMask = nStateMask;
+ item.lParam = lParam;
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item);
+ }
+
+ BOOL GetItemText(HTREEITEM hItem, LPTSTR lpstrText, int nLen) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpstrText != NULL);
+
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_TEXT;
+ item.pszText = lpstrText;
+ item.cchTextMax = nLen;
+
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetItemText(HTREEITEM hItem, BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_TEXT;
+
+ LPTSTR lpstrText = NULL;
+ BOOL bRet = FALSE;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrText = new TCHAR[nLen]);
+ if(lpstrText == NULL)
+ break;
+ lpstrText[0] = NULL;
+ item.pszText = lpstrText;
+ item.cchTextMax = nLen;
+ bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ if(!bRet || (lstrlen(item.pszText) < nLen - 1))
+ break;
+ delete [] lpstrText;
+ lpstrText = NULL;
+ }
+
+ if(lpstrText != NULL)
+ {
+ if(bRet)
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ delete [] lpstrText;
+ }
+
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL GetItemText(HTREEITEM hItem, _CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_TEXT;
+
+ strText.Empty();
+ BOOL bRet = FALSE;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ item.pszText = strText.GetBufferSetLength(nLen);
+ if(item.pszText == NULL)
+ {
+ bRet = FALSE;
+ break;
+ }
+ item.cchTextMax = nLen;
+ bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ if(!bRet || (lstrlen(item.pszText) < nLen - 1))
+ break;
+ }
+ strText.ReleaseBuffer();
+ return bRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL SetItemText(HTREEITEM hItem, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(hItem, TVIF_TEXT, lpszItem, 0, 0, 0, 0, NULL);
+ }
+
+ BOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE;
+ BOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ if (bRes)
+ {
+ nImage = item.iImage;
+ nSelectedImage = item.iSelectedImage;
+ }
+ return bRes;
+ }
+
+ BOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(hItem, TVIF_IMAGE|TVIF_SELECTEDIMAGE, NULL, nImage, nSelectedImage, 0, 0, NULL);
+ }
+
+ UINT GetItemState(HTREEITEM hItem, UINT nStateMask) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ return (((UINT)::SendMessage(m_hWnd, TVM_GETITEMSTATE, (WPARAM)hItem, (LPARAM)nStateMask)) & nStateMask);
+#else // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE))
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_STATE;
+ item.state = 0;
+ item.stateMask = nStateMask;
+ ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ return (item.state & nStateMask);
+#endif // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE))
+ }
+
+ BOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(hItem, TVIF_STATE, NULL, 0, 0, nState, nStateMask, NULL);
+ }
+
+ DWORD_PTR GetItemData(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_PARAM;
+ BOOL bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ return (DWORD_PTR)(bRet ? item.lParam : NULL);
+ }
+
+ BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(hItem, TVIF_PARAM, NULL, 0, 0, 0, 0, (LPARAM)dwData);
+ }
+
+ CEdit GetEditControl() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CEdit((HWND)::SendMessage(m_hWnd, TVM_GETEDITCONTROL, 0, 0L));
+ }
+
+ UINT GetVisibleCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TVM_GETVISIBLECOUNT, 0, 0L);
+ }
+
+ BOOL GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ *(HTREEITEM*)lpRect = hItem;
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly, (LPARAM)lpRect);
+ }
+
+ BOOL ItemHasChildren(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVITEM item = { 0 };
+ item.hItem = hItem;
+ item.mask = TVIF_CHILDREN;
+ ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
+ return item.cChildren;
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetToolTips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L));
+ }
+
+ CToolTipCtrl SetToolTips(HWND hWndTT)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L));
+ }
+#endif // !_WIN32_WCE
+
+ int GetISearchString(LPTSTR lpstr) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TVM_GETISEARCHSTRING, 0, (LPARAM)lpstr);
+ }
+
+ // checkboxes only
+ BOOL GetCheckState(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & TVS_CHECKBOXES) != 0);
+ UINT uRet = GetItemState(hItem, TVIS_STATEIMAGEMASK);
+ return (uRet >> 12) - 1;
+ }
+
+ BOOL SetCheckState(HTREEITEM hItem, BOOL bCheck)
+ {
+ int nCheck = bCheck ? 2 : 1; // one based index
+ return SetItemState(hItem, INDEXTOSTATEIMAGEMASK(nCheck), TVIS_STATEIMAGEMASK);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_GETBKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetBkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_SETBKCOLOR, 0, (LPARAM)clr);
+ }
+
+ COLORREF GetInsertMarkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_GETINSERTMARKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetInsertMarkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_SETINSERTMARKCOLOR, 0, (LPARAM)clr);
+ }
+
+ int GetItemHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TVM_GETITEMHEIGHT, 0, 0L);
+ }
+
+ int SetItemHeight(int cyHeight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TVM_SETITEMHEIGHT, cyHeight, 0L);
+ }
+
+ int GetScrollTime() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TVM_GETSCROLLTIME, 0, 0L);
+ }
+
+ int SetScrollTime(int nScrollTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TVM_SETSCROLLTIME, nScrollTime, 0L);
+ }
+
+ COLORREF GetTextColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_GETTEXTCOLOR, 0, 0L);
+ }
+
+ COLORREF SetTextColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)clr);
+ }
+
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ COLORREF GetLineColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_GETLINECOLOR, 0, 0L);
+ }
+
+ COLORREF SetLineColor(COLORREF clrNew /*= CLR_DEFAULT*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TVM_SETLINECOLOR, 0, (LPARAM)clrNew);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetItem(LPTVITEMEX pItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem);
+ }
+
+ BOOL SetItem(LPTVITEMEX pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+ DWORD GetExtendedStyle() const
+ {
+#ifndef TVM_GETEXTENDEDSTYLE
+ const UINT TVM_GETEXTENDEDSTYLE = (TV_FIRST + 45);
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TVM_GETEXTENDEDSTYLE, 0, 0L);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask)
+ {
+#ifndef TVM_SETEXTENDEDSTYLE
+ const UINT TVM_SETEXTENDEDSTYLE = (TV_FIRST + 44);
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TVM_SETEXTENDEDSTYLE, dwMask, dwStyle);
+ }
+
+#if (_WIN32_WINNT >= 0x0600)
+ BOOL SetAutoScrollInfo(UINT uPixPerSec, UINT uUpdateTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETAUTOSCROLLINFO, (WPARAM)uPixPerSec, (LPARAM)uUpdateTime);
+ }
+
+ DWORD GetSelectedCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TVM_GETSELECTEDCOUNT, 0, 0L);
+ }
+
+ BOOL GetItemPartRect(HTREEITEM hItem, TVITEMPART partID, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVGETITEMPARTRECTINFO gipri = { hItem, lpRect, partID };
+ return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMPARTRECT, 0, (LPARAM)&gipri);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct);
+ }
+
+ HTREEITEM InsertItem(LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter);
+ }
+
+ HTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter);
+ }
+
+ HTREEITEM InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam,
+ HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVINSERTSTRUCT tvis = { 0 };
+ tvis.hParent = hParent;
+ tvis.hInsertAfter = hInsertAfter;
+ tvis.item.mask = nMask;
+ tvis.item.pszText = (LPTSTR) lpszItem;
+ tvis.item.iImage = nImage;
+ tvis.item.iSelectedImage = nSelectedImage;
+ tvis.item.state = nState;
+ tvis.item.stateMask = nStateMask;
+ tvis.item.lParam = lParam;
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis);
+ }
+
+ BOOL DeleteItem(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem);
+ }
+
+ BOOL DeleteAllItems()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
+ }
+
+ BOOL Expand(HTREEITEM hItem, UINT nCode = TVE_EXPAND)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_EXPAND, nCode, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetChildItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetParentItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetFirstVisibleItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L);
+ }
+
+ HTREEITEM GetNextVisibleItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetPrevVisibleItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem);
+ }
+
+ HTREEITEM GetSelectedItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L);
+ }
+
+ HTREEITEM GetDropHilightItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L);
+ }
+
+ HTREEITEM GetRootItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L);
+ }
+
+#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+ HTREEITEM GetLastVisibleItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L);
+ }
+#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0600)
+ HTREEITEM GetNextSelectedItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0600)
+
+ BOOL Select(HTREEITEM hItem, UINT nCode)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, nCode, (LPARAM)hItem);
+ }
+
+ BOOL SelectItem(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem);
+ }
+
+ BOOL SelectDropTarget(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItem);
+ }
+
+ BOOL SelectSetFirstVisible(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hItem);
+ }
+
+ CEdit EditLabel(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CEdit((HWND)::SendMessage(m_hWnd, TVM_EDITLABEL, 0, (LPARAM)hItem));
+ }
+
+ BOOL EndEditLabelNow(BOOL bCancel)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_ENDEDITLABELNOW, bCancel, 0L);
+ }
+
+ HTREEITEM HitTest(TVHITTESTINFO* pHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo);
+ }
+
+ HTREEITEM HitTest(POINT pt, UINT* pFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVHITTESTINFO hti = { 0 };
+ hti.pt = pt;
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti);
+ if (pFlags != NULL)
+ *pFlags = hti.flags;
+ return hTreeItem;
+ }
+
+ BOOL SortChildren(HTREEITEM hItem, BOOL bRecurse = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDREN, (WPARAM)bRecurse, (LPARAM)hItem);
+ }
+
+ BOOL EnsureVisible(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem);
+ }
+
+ BOOL SortChildrenCB(LPTVSORTCB pSort, BOOL bRecurse = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDRENCB, (WPARAM)bRecurse, (LPARAM)pSort);
+ }
+
+ CImageList RemoveImageList(int nImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageList, NULL));
+ }
+
+ CImageList CreateDragImage(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem));
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL SetInsertMark(HTREEITEM hTreeItem, BOOL bAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, bAfter, (LPARAM)hTreeItem);
+ }
+
+ BOOL RemoveInsertMark()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, 0, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501)
+ HTREEITEM MapAccIDToHTREEITEM(UINT uID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L);
+ }
+
+ UINT MapHTREEITEMToAccID(HTREEITEM hTreeItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TVM_MAPHTREEITEMTOACCID, (WPARAM)hTreeItem, 0L);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+ void ShowInfoTip(HTREEITEM hItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TVM_SHOWINFOTIP, 0, (LPARAM)hItem);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+};
+
+typedef CTreeViewCtrlT<ATL::CWindow> CTreeViewCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTreeViewCtrlEx
+
+// forward declaration
+template <class TBase> class CTreeViewCtrlExT;
+
+// Note: TBase here is for CTreeViewCtrlExT, and not for CTreeItemT itself
+template <class TBase>
+class CTreeItemT
+{
+public:
+ HTREEITEM m_hTreeItem;
+ CTreeViewCtrlExT<TBase>* m_pTreeView;
+
+// Construction
+ CTreeItemT(HTREEITEM hTreeItem = NULL, CTreeViewCtrlExT<TBase>* pTreeView = NULL) : m_hTreeItem(hTreeItem), m_pTreeView(pTreeView)
+ { }
+
+ CTreeItemT(const CTreeItemT<TBase>& posSrc)
+ {
+ *this = posSrc;
+ }
+
+ operator HTREEITEM() { return m_hTreeItem; }
+
+ CTreeItemT<TBase>& operator =(const CTreeItemT<TBase>& itemSrc)
+ {
+ m_hTreeItem = itemSrc.m_hTreeItem;
+ m_pTreeView = itemSrc.m_pTreeView;
+ return *this;
+ }
+
+// Attributes
+ CTreeViewCtrlExT<TBase>* GetTreeView() const { return m_pTreeView; }
+
+ BOOL operator !() const { return m_hTreeItem == NULL; }
+
+ BOOL IsNull() const { return m_hTreeItem == NULL; }
+
+ BOOL GetRect(LPRECT lpRect, BOOL bTextOnly) const;
+ BOOL GetText(LPTSTR lpstrText, int nLen) const;
+#ifndef _ATL_NO_COM
+ BOOL GetText(BSTR& bstrText) const;
+#endif // !_ATL_NO_COM
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL GetText(_CSTRING_NS::CString& strText) const;
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL SetText(LPCTSTR lpszItem);
+ BOOL GetImage(int& nImage, int& nSelectedImage) const;
+ BOOL SetImage(int nImage, int nSelectedImage);
+ UINT GetState(UINT nStateMask) const;
+ BOOL SetState(UINT nState, UINT nStateMask);
+ DWORD_PTR GetData() const;
+ BOOL SetData(DWORD_PTR dwData);
+ BOOL SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam);
+
+// Operations
+ CTreeItemT<TBase> InsertAfter(LPCTSTR lpstrItem, HTREEITEM hItemAfter, int nImageIndex)
+ {
+ return _Insert(lpstrItem, nImageIndex, hItemAfter);
+ }
+
+ CTreeItemT<TBase> AddHead(LPCTSTR lpstrItem, int nImageIndex)
+ {
+ return _Insert(lpstrItem, nImageIndex, TVI_FIRST);
+ }
+
+ CTreeItemT<TBase> AddTail(LPCTSTR lpstrItem, int nImageIndex)
+ {
+ return _Insert(lpstrItem, nImageIndex, TVI_LAST);
+ }
+
+ CTreeItemT<TBase> GetChild() const;
+ CTreeItemT<TBase> GetNext(UINT nCode) const;
+ CTreeItemT<TBase> GetNextSibling() const;
+ CTreeItemT<TBase> GetPrevSibling() const;
+ CTreeItemT<TBase> GetParent() const;
+ CTreeItemT<TBase> GetFirstVisible() const;
+ CTreeItemT<TBase> GetNextVisible() const;
+ CTreeItemT<TBase> GetPrevVisible() const;
+ CTreeItemT<TBase> GetSelected() const;
+ CTreeItemT<TBase> GetDropHilight() const;
+ CTreeItemT<TBase> GetRoot() const;
+#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+ CTreeItemT<TBase> GetLastVisible() const;
+#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0600)
+ CTreeItemT<TBase> GetNextSelected() const;
+#endif // (_WIN32_IE >= 0x0600)
+ BOOL HasChildren() const;
+ BOOL Delete();
+ BOOL Expand(UINT nCode = TVE_EXPAND);
+ BOOL Select(UINT nCode);
+ BOOL Select();
+ BOOL SelectDropTarget();
+ BOOL SelectSetFirstVisible();
+ HWND EditLabel();
+ HIMAGELIST CreateDragImage();
+ BOOL SortChildren(BOOL bRecurse = FALSE);
+ BOOL EnsureVisible();
+ CTreeItemT<TBase> _Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter);
+ int GetImageIndex() const;
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL SetInsertMark(BOOL bAfter);
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+#if (_WIN32_WINNT >= 0x0501)
+ UINT MapHTREEITEMToAccID() const;
+#endif // (_WIN32_WINNT >= 0x0501)
+#if (_WIN32_WINNT >= 0x0600)
+ void ShowInfoTip();
+ BOOL GetPartRect(TVITEMPART partID, LPRECT lpRect) const;
+#endif // (_WIN32_WINNT >= 0x0600)
+};
+
+typedef CTreeItemT<ATL::CWindow> CTreeItem;
+
+
+template <class TBase>
+class CTreeViewCtrlExT : public CTreeViewCtrlT< TBase >
+{
+public:
+// Constructors
+ CTreeViewCtrlExT(HWND hWnd = NULL) : CTreeViewCtrlT< TBase >(hWnd)
+ { }
+
+ CTreeViewCtrlExT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Operations (overides that return CTreeItem)
+ CTreeItemT<TBase> InsertItem(LPTVINSERTSTRUCT lpInsertStruct)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct);
+ return CTreeItemT<TBase>(hTreeItem, this);
+ }
+
+ CTreeItemT<TBase> InsertItem(LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter);
+ }
+
+ CTreeItemT<TBase> InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter);
+ }
+
+ CTreeItemT<TBase> GetNextItem(HTREEITEM hItem, UINT nCode) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetChildItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetNextSiblingItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetPrevSiblingItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetParentItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetFirstVisibleItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetNextVisibleItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetPrevVisibleItem(HTREEITEM hItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetSelectedItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetDropHilightItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> GetRootItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+ CTreeItemT<TBase> GetLastVisibleItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0600)
+ CTreeItemT<TBase> GetNextSelectedItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+#endif // (_WIN32_IE >= 0x0600)
+
+ CTreeItemT<TBase> HitTest(TVHITTESTINFO* pHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+ CTreeItemT<TBase> InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam,
+ HTREEITEM hParent, HTREEITEM hInsertAfter)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVINSERTSTRUCT tvis = { 0 };
+ tvis.hParent = hParent;
+ tvis.hInsertAfter = hInsertAfter;
+ tvis.item.mask = nMask;
+ tvis.item.pszText = (LPTSTR) lpszItem;
+ tvis.item.iImage = nImage;
+ tvis.item.iSelectedImage = nSelectedImage;
+ tvis.item.state = nState;
+ tvis.item.stateMask = nStateMask;
+ tvis.item.lParam = lParam;
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis);
+ return CTreeItemT<TBase>(hTreeItem, this);
+ }
+
+ CTreeItemT<TBase> HitTest(POINT pt, UINT* pFlags) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TVHITTESTINFO hti = { 0 };
+ hti.pt = pt;
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti);
+ if (pFlags != NULL)
+ *pFlags = hti.flags;
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+
+#if (_WIN32_WINNT >= 0x0501)
+ CTreeItemT<TBase> MapAccIDToHTREEITEM(UINT uID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L);
+ return CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+};
+
+typedef CTreeViewCtrlExT<ATL::CWindow> CTreeViewCtrlEx;
+
+
+// CTreeItem inline methods
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetRect(LPRECT lpRect, BOOL bTextOnly) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemRect(m_hTreeItem,lpRect,bTextOnly);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetNext(UINT nCode) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetNextItem(m_hTreeItem,nCode);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetChild() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetChildItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextSibling() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetNextSiblingItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetPrevSibling() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetPrevSiblingItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetParent() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetParentItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetFirstVisible() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetFirstVisibleItem();
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextVisible() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetNextVisibleItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetPrevVisible() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetPrevVisibleItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetSelected() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetSelectedItem();
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetDropHilight() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetDropHilightItem();
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetRoot() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetRootItem();
+}
+
+#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetLastVisible() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetLastVisibleItem();
+}
+#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0600)
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextSelected() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetNextSelectedItem();
+}
+#endif // (_WIN32_IE >= 0x0600)
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetText(LPTSTR lpstrText, int nLen) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemText(m_hTreeItem, lpstrText, nLen);
+}
+
+#ifndef _ATL_NO_COM
+#ifdef _OLEAUTO_H_
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetText(BSTR& bstrText) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemText(m_hTreeItem, bstrText);
+}
+#endif // _OLEAUTO_H_
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetText(_CSTRING_NS::CString& strText) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemText(m_hTreeItem, strText);
+}
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetImage(int& nImage, int& nSelectedImage) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemImage(m_hTreeItem,nImage,nSelectedImage);
+}
+
+template <class TBase>
+inline UINT CTreeItemT<TBase>::GetState(UINT nStateMask) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemState(m_hTreeItem,nStateMask);
+}
+
+template <class TBase>
+inline DWORD_PTR CTreeItemT<TBase>::GetData() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemData(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetItem(UINT nMask, LPCTSTR lpszItem, int nImage,
+ int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetItem(m_hTreeItem, nMask, lpszItem, nImage, nSelectedImage, nState, nStateMask, lParam);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetText(LPCTSTR lpszItem)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetItemText(m_hTreeItem,lpszItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetImage(int nImage, int nSelectedImage)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetItemImage(m_hTreeItem,nImage,nSelectedImage);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetState(UINT nState, UINT nStateMask)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetItemState(m_hTreeItem,nState,nStateMask);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetData(DWORD_PTR dwData)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetItemData(m_hTreeItem,dwData);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::HasChildren() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->ItemHasChildren(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::Delete()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->DeleteItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::Expand(UINT nCode /*= TVE_EXPAND*/)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->Expand(m_hTreeItem,nCode);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::Select(UINT nCode)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->Select(m_hTreeItem,nCode);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::Select()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SelectItem(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SelectDropTarget()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SelectDropTarget(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SelectSetFirstVisible()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SelectSetFirstVisible(m_hTreeItem);
+}
+
+template <class TBase>
+inline HWND CTreeItemT<TBase>::EditLabel()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->EditLabel(m_hTreeItem);
+}
+
+template <class TBase>
+inline HIMAGELIST CTreeItemT<TBase>::CreateDragImage()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->CreateDragImage(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SortChildren(BOOL bRecurse /*= FALSE*/)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SortChildren(m_hTreeItem, bRecurse);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::EnsureVisible()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->EnsureVisible(m_hTreeItem);
+}
+
+template <class TBase>
+inline CTreeItemT<TBase> CTreeItemT<TBase>::_Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ TVINSERTSTRUCT ins = { 0 };
+ ins.hParent = m_hTreeItem;
+ ins.hInsertAfter = hItemAfter;
+ ins.item.mask = TVIF_TEXT;
+ ins.item.pszText = (LPTSTR)lpstrItem;
+ if(nImageIndex != -1)
+ {
+ ins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ ins.item.iImage = nImageIndex;
+ ins.item.iSelectedImage = nImageIndex;
+ }
+ return CTreeItemT<TBase>(m_pTreeView->InsertItem(&ins), m_pTreeView);
+}
+
+template <class TBase>
+inline int CTreeItemT<TBase>::GetImageIndex() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ TVITEM item = { 0 };
+ item.mask = TVIF_HANDLE | TVIF_IMAGE;
+ item.hItem = m_hTreeItem;
+ m_pTreeView->GetItem(&item);
+ return item.iImage;
+}
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::SetInsertMark(BOOL bAfter)
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->SetInsertMark(m_hTreeItem, bAfter);
+}
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501)
+template <class TBase>
+inline UINT CTreeItemT<TBase>::MapHTREEITEMToAccID() const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->MapHTREEITEMToAccID(m_hTreeItem);
+}
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+template <class TBase>
+inline void CTreeItemT<TBase>::ShowInfoTip()
+{
+ ATLASSERT(m_pTreeView != NULL);
+ m_pTreeView->ShowInfoTip(m_hTreeItem);
+}
+
+template <class TBase>
+inline BOOL CTreeItemT<TBase>::GetPartRect(TVITEMPART partID, LPRECT lpRect) const
+{
+ ATLASSERT(m_pTreeView != NULL);
+ return m_pTreeView->GetItemPartRect(m_hTreeItem, partID, lpRect);
+}
+#endif // (_WIN32_WINNT >= 0x0600)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CToolBarCtrl
+
+template <class TBase>
+class CToolBarCtrlT : public TBase
+{
+public:
+// Construction
+ CToolBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CToolBarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return TOOLBARCLASSNAME;
+ }
+
+ BOOL IsButtonEnabled(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0L);
+ }
+
+ BOOL IsButtonChecked(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONCHECKED, nID, 0L);
+ }
+
+ BOOL IsButtonPressed(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0L);
+ }
+
+ BOOL IsButtonHidden(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return(BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0L);
+ }
+
+ BOOL IsButtonIndeterminate(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONINDETERMINATE, nID, 0L);
+ }
+
+ int GetState(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L);
+ }
+
+ BOOL SetState(int nID, UINT nState)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0));
+ }
+
+ BOOL GetButton(int nIndex, LPTBBUTTON lpButton) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETBUTTON, nIndex, (LPARAM)lpButton);
+ }
+
+ int GetButtonCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_BUTTONCOUNT, 0, 0L);
+ }
+
+ BOOL GetItemRect(int nIndex, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETITEMRECT, nIndex, (LPARAM)lpRect);
+ }
+
+ void SetButtonStructSize(int nSize = sizeof(TBBUTTON))
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, nSize, 0L);
+ }
+
+ BOOL SetButtonSize(SIZE size)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy));
+ }
+
+ BOOL SetButtonSize(int cx, int cy)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cy));
+ }
+
+ BOOL SetBitmapSize(SIZE size)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy));
+ }
+
+ BOOL SetBitmapSize(int cx, int cy)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(cx, cy));
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetToolTips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TB_GETTOOLTIPS, 0, 0L));
+ }
+
+ void SetToolTips(HWND hWndToolTip)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ void SetNotifyWnd(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)hWnd, 0L);
+ }
+
+ int GetRows() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETROWS, 0, 0L);
+ }
+
+ void SetRows(int nRows, BOOL bLarger, LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETROWS, MAKELPARAM(nRows, bLarger), (LPARAM)lpRect);
+ }
+
+ BOOL SetCmdID(int nIndex, UINT nID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETCMDID, nIndex, nID);
+ }
+
+ DWORD GetBitmapFlags() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L);
+ }
+
+ int GetBitmap(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETBITMAP, nID, 0L);
+ }
+
+ int GetButtonText(int nID, LPTSTR lpstrText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETBUTTONTEXT, nID, (LPARAM)lpstrText);
+ }
+
+ // nIndex - IE5 or higher only
+ CImageList GetImageList(int nIndex = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETIMAGELIST, nIndex, 0L));
+ }
+
+ // nIndex - IE5 or higher only
+ CImageList SetImageList(HIMAGELIST hImageList, int nIndex = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETIMAGELIST, nIndex, (LPARAM)hImageList));
+ }
+
+ // nIndex - IE5 or higher only
+ CImageList GetDisabledImageList(int nIndex = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETDISABLEDIMAGELIST, nIndex, 0L));
+ }
+
+ // nIndex - IE5 or higher only
+ CImageList SetDisabledImageList(HIMAGELIST hImageList, int nIndex = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETDISABLEDIMAGELIST, nIndex, (LPARAM)hImageList));
+ }
+
+#ifndef _WIN32_WCE
+ // nIndex - IE5 or higher only
+ CImageList GetHotImageList(int nIndex = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETHOTIMAGELIST, nIndex, 0L));
+ }
+
+ // nIndex - IE5 or higher only
+ CImageList SetHotImageList(HIMAGELIST hImageList, int nIndex = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETHOTIMAGELIST, nIndex, (LPARAM)hImageList));
+ }
+#endif // !_WIN32_WCE
+
+ DWORD GetStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_GETSTYLE, 0, 0L);
+ }
+
+ void SetStyle(DWORD dwStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETSTYLE, 0, dwStyle);
+ }
+
+ DWORD GetButtonSize() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L);
+ }
+
+ void GetButtonSize(SIZE& size) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L);
+ size.cx = LOWORD(dwRet);
+ size.cy = HIWORD(dwRet);
+ }
+
+ BOOL GetRect(int nID, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETRECT, nID, (LPARAM)lpRect);
+ }
+
+ int GetTextRows() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0L);
+ }
+
+ BOOL SetButtonWidth(int cxMin, int cxMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cxMin, cxMax));
+ }
+
+ BOOL SetIndent(int nIndent)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETINDENT, nIndent, 0L);
+ }
+
+ BOOL SetMaxTextRows(int nMaxTextRows)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, nMaxTextRows, 0L);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+#ifndef _WIN32_WCE
+ BOOL GetAnchorHighlight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETANCHORHIGHLIGHT, 0, 0L);
+ }
+
+ BOOL SetAnchorHighlight(BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETANCHORHIGHLIGHT, bEnable, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ int GetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETBUTTONINFO, nID, (LPARAM)lptbbi);
+ }
+
+ BOOL SetButtonInfo(int nID, LPTBBUTTONINFO lptbbi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)lptbbi);
+ }
+
+ BOOL SetButtonInfo(int nID, DWORD dwMask, BYTE Style, BYTE State, LPCTSTR lpszItem,
+ int iImage, WORD cx, int iCommand, DWORD_PTR lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBBUTTONINFO tbbi = { 0 };
+ tbbi.cbSize = sizeof(TBBUTTONINFO);
+ tbbi.dwMask = dwMask;
+ tbbi.idCommand = iCommand;
+ tbbi.iImage = iImage;
+ tbbi.fsState = State;
+ tbbi.fsStyle = Style;
+ tbbi.cx = cx;
+ tbbi.pszText = (LPTSTR) lpszItem;
+ tbbi.lParam = lParam;
+ return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)&tbbi);
+ }
+
+#ifndef _WIN32_WCE
+ int GetHotItem() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETHOTITEM, 0, 0L);
+ }
+
+ int SetHotItem(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_SETHOTITEM, nItem, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL IsButtonHighlighted(int nButtonID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONHIGHLIGHTED, nButtonID, 0L);
+ }
+
+ DWORD SetDrawTextFlags(DWORD dwMask, DWORD dwFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_SETDRAWTEXTFLAGS, dwMask, dwFlags);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetColorScheme(LPCOLORSCHEME lpcs) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETCOLORSCHEME, 0, (LPARAM)lpcs);
+ }
+
+ void SetColorScheme(LPCOLORSCHEME lpcs)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETCOLORSCHEME, 0, (LPARAM)lpcs);
+ }
+
+ DWORD GetExtendedStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_GETEXTENDEDSTYLE, 0, 0L);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, dwStyle);
+ }
+
+ void GetInsertMark(LPTBINSERTMARK lptbim) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_GETINSERTMARK, 0, (LPARAM)lptbim);
+ }
+
+ void SetInsertMark(LPTBINSERTMARK lptbim)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETINSERTMARK, 0, (LPARAM)lptbim);
+ }
+
+ COLORREF GetInsertMarkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TB_GETINSERTMARKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetInsertMarkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, TB_SETINSERTMARKCOLOR, 0, (LPARAM)clr);
+ }
+
+ BOOL GetMaxSize(LPSIZE lpSize) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETMAXSIZE, 0, (LPARAM)lpSize);
+ }
+
+ void GetPadding(LPSIZE lpSizePadding) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpSizePadding != NULL);
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETPADDING, 0, 0L);
+ lpSizePadding->cx = GET_X_LPARAM(dwRet);
+ lpSizePadding->cy = GET_Y_LPARAM(dwRet);
+ }
+
+ void SetPadding(int cx, int cy, LPSIZE lpSizePadding = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_SETPADDING, 0, MAKELPARAM(cx, cy));
+ if(lpSizePadding != NULL)
+ {
+ lpSizePadding->cx = GET_X_LPARAM(dwRet);
+ lpSizePadding->cy = GET_Y_LPARAM(dwRet);
+ }
+ }
+
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ int GetString(int nString, LPTSTR lpstrString, int cchMaxLen) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(cchMaxLen, nString), (LPARAM)lpstrString);
+ }
+
+ int GetStringBSTR(int nString, BSTR& bstrString) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrString == NULL);
+ int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL));
+ if(nLength != -1)
+ {
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(nLength + 1);
+ if(lpstrText != NULL)
+ {
+ nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstrText);
+ if(nLength != -1)
+ bstrString = ::SysAllocString(T2OLE(lpstrText));
+ }
+ else
+ {
+ nLength = -1;
+ }
+ }
+
+ return nLength;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetString(int nString, _CSTRING_NS::CString& str) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL));
+ if(nLength != -1)
+ {
+ LPTSTR lpstr = str.GetBufferSetLength(nLength + 1);
+ if(lpstr != NULL)
+ nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstr);
+ else
+ nLength = -1;
+ str.ReleaseBuffer();
+ }
+ return nLength;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501)
+ void GetMetrics(LPTBMETRICS lptbm) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_GETMETRICS, 0, (LPARAM)lptbm);
+ }
+
+ void SetMetrics(LPTBMETRICS lptbm)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETMETRICS, 0, (LPARAM)lptbm);
+ }
+
+ void SetWindowTheme(LPCWSTR lpstrTheme)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_WINNT >= 0x0600)
+ CImageList GetPressedImageList(int nIndex = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETPRESSEDIMAGELIST, nIndex, 0L));
+ }
+
+ CImageList SetPressedImageList(HIMAGELIST hImageList, int nIndex = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETPRESSEDIMAGELIST, nIndex, (LPARAM)hImageList));
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ BOOL EnableButton(int nID, BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0));
+ }
+
+ BOOL CheckButton(int nID, BOOL bCheck = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_CHECKBUTTON, nID, MAKELPARAM(bCheck, 0));
+ }
+
+ BOOL PressButton(int nID, BOOL bPress = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0));
+ }
+
+ BOOL HideButton(int nID, BOOL bHide = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0));
+ }
+
+ BOOL Indeterminate(int nID, BOOL bIndeterminate = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_INDETERMINATE, nID, MAKELPARAM(bIndeterminate, 0));
+ }
+
+ int AddBitmap(int nNumButtons, UINT nBitmapID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBADDBITMAP tbab = { 0 };
+ tbab.hInst = ModuleHelper::GetResourceInstance();
+ ATLASSERT(tbab.hInst != NULL);
+ tbab.nID = nBitmapID;
+ return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab);
+ }
+
+ int AddBitmap(int nNumButtons, HBITMAP hBitmap)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBADDBITMAP tbab = { 0 };
+ tbab.hInst = NULL;
+ tbab.nID = (UINT_PTR)hBitmap;
+ return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab);
+ }
+
+ BOOL AddButtons(int nNumButtons, LPTBBUTTON lpButtons)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_ADDBUTTONS, nNumButtons, (LPARAM)lpButtons);
+ }
+
+ BOOL InsertButton(int nIndex, LPTBBUTTON lpButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)lpButton);
+ }
+
+ BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap,
+ INT_PTR iString, DWORD_PTR lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBBUTTON tbb = { 0 };
+ tbb.fsStyle = Style;
+ tbb.fsState = State;
+ tbb.idCommand = iCommand;
+ tbb.iBitmap = iBitmap;
+ tbb.iString = iString;
+ tbb.dwData = lParam;
+ return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)&tbb);
+ }
+
+ BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap,
+ LPCTSTR lpszItem, DWORD_PTR lParam)
+ {
+ return InsertButton(nIndex, iCommand, Style, State, iBitmap, (INT_PTR)lpszItem, lParam);
+ }
+
+ BOOL AddButton(LPTBBUTTON lpButton)
+ {
+ return InsertButton(-1, lpButton);
+ }
+
+ BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam)
+ {
+ return InsertButton(-1, iCommand, Style, State, iBitmap, iString, lParam);
+ }
+
+ BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam)
+ {
+ return InsertButton(-1, iCommand, Style, State, iBitmap, lpszItem, lParam);
+ }
+
+ BOOL DeleteButton(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_DELETEBUTTON, nIndex, 0L);
+ }
+
+ UINT CommandToIndex(UINT nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TB_COMMANDTOINDEX, nID, 0L);
+ }
+
+#ifndef _WIN32_WCE
+ void SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBSAVEPARAMS tbs = { 0 };
+ tbs.hkr = hKeyRoot;
+ tbs.pszSubKey = lpszSubKey;
+ tbs.pszValueName = lpszValueName;
+ ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs);
+ }
+
+ void RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TBSAVEPARAMS tbs = { 0 };
+ tbs.hkr = hKeyRoot;
+ tbs.pszSubKey = lpszSubKey;
+ tbs.pszValueName = lpszValueName;
+ ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs);
+ }
+
+ void Customize()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_CUSTOMIZE, 0, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ int AddString(UINT nStringID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)ModuleHelper::GetResourceInstance(), (LPARAM)nStringID);
+ }
+
+ int AddStrings(LPCTSTR lpszStrings)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings);
+ }
+
+ void AutoSize()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0L);
+ }
+
+ BOOL ChangeBitmap(int nID, int nBitmap)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_CHANGEBITMAP, nID, MAKELPARAM(nBitmap, 0));
+ }
+
+ int LoadImages(int nBitmapID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)ModuleHelper::GetResourceInstance());
+ }
+
+ int LoadStdImages(int nBitmapID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)HINST_COMMCTRL);
+ }
+
+ BOOL ReplaceBitmap(LPTBREPLACEBITMAP ptbrb)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_REPLACEBITMAP, 0, (LPARAM)ptbrb);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ int HitTest(LPPOINT lpPoint) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TB_HITTEST, 0, (LPARAM)lpPoint);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL InsertMarkHitTest(LPPOINT lpPoint, LPTBINSERTMARK lptbim) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)lptbim);
+ }
+
+ BOOL InsertMarkHitTest(int x, int y, LPTBINSERTMARK lptbim) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ POINT pt = { x, y };
+ return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)&pt, (LPARAM)lptbim);
+ }
+
+ BOOL MapAccelerator(TCHAR chAccel, int& nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_MAPACCELERATOR, (WPARAM)chAccel, (LPARAM)&nID);
+ }
+
+ BOOL MarkButton(int nID, BOOL bHighlight = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_MARKBUTTON, nID, MAKELPARAM(bHighlight, 0));
+ }
+
+ BOOL MoveButton(int nOldPos, int nNewPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TB_MOVEBUTTON, nOldPos, nNewPos);
+ }
+
+ HRESULT GetObject(REFIID iid, LPVOID* ppvObject)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HRESULT)::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&iid, (LPARAM)ppvObject);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+};
+
+typedef CToolBarCtrlT<ATL::CWindow> CToolBarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CStatusBarCtrl
+
+template <class TBase>
+class CStatusBarCtrlT : public TBase
+{
+public:
+// Constructors
+ CStatusBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CStatusBarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Methods
+ static LPCTSTR GetWndClassName()
+ {
+ return STATUSCLASSNAME;
+ }
+
+ int GetParts(int nParts, int* pParts) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, SB_GETPARTS, nParts, (LPARAM)pParts);
+ }
+
+ BOOL SetParts(int nParts, int* pWidths)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_SETPARTS, nParts, (LPARAM)pWidths);
+ }
+
+ int GetTextLength(int nPane, int* pType = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L);
+ if (pType != NULL)
+ *pType = (int)(short)HIWORD(dwRet);
+ return (int)(short)LOWORD(dwRet);
+ }
+
+ int GetText(int nPane, LPTSTR lpszText, int* pType = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane, (LPARAM)lpszText);
+ if(pType != NULL)
+ *pType = (int)(short)HIWORD(dwRet);
+ return (int)(short)LOWORD(dwRet);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetTextBSTR(int nPane, BSTR& bstrText, int* pType = NULL) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ ATLASSERT(bstrText == NULL);
+ int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L));
+ if(nLength == 0)
+ return FALSE;
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(nLength + 1);
+ if(lpstrText == NULL)
+ return FALSE;
+
+ if(!GetText(nPane, lpstrText, pType))
+ return FALSE;
+
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetText(int nPane, _CSTRING_NS::CString& strText, int* pType = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L));
+ if(nLength == 0)
+ return 0;
+
+ LPTSTR lpstr = strText.GetBufferSetLength(nLength);
+ if(lpstr == NULL)
+ return 0;
+ return GetText(nPane, lpstr, pType);
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL SetText(int nPane, LPCTSTR lpszText, int nType = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ return (BOOL)::SendMessage(m_hWnd, SB_SETTEXT, (nPane | nType), (LPARAM)lpszText);
+ }
+
+ BOOL GetRect(int nPane, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ return (BOOL)::SendMessage(m_hWnd, SB_GETRECT, nPane, (LPARAM)lpRect);
+ }
+
+ BOOL GetBorders(int* pBorders) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)pBorders);
+ }
+
+ BOOL GetBorders(int& nHorz, int& nVert, int& nSpacing) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int borders[3] = { 0, 0, 0 };
+ BOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)&borders);
+ if(bResult)
+ {
+ nHorz = borders[0];
+ nVert = borders[1];
+ nSpacing = borders[2];
+ }
+ return bResult;
+ }
+
+ void SetMinHeight(int nMin)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, SB_SETMINHEIGHT, nMin, 0L);
+ }
+
+ BOOL SetSimple(BOOL bSimple = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_SIMPLE, bSimple, 0L);
+ }
+
+ BOOL IsSimple() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_ISSIMPLE, 0, 0L);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, SB_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+
+ void GetTipText(int nPane, LPTSTR lpstrText, int nSize) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ ::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, nSize), (LPARAM)lpstrText);
+ }
+
+ void SetTipText(int nPane, LPCTSTR lpstrText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ ::SendMessage(m_hWnd, SB_SETTIPTEXT, nPane, (LPARAM)lpstrText);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
+ COLORREF SetBkColor(COLORREF clrBk)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, SB_SETBKCOLOR, 0, (LPARAM)clrBk);
+ }
+
+ HICON GetIcon(int nPane) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ return (HICON)::SendMessage(m_hWnd, SB_GETICON, nPane, 0L);
+ }
+
+ BOOL SetIcon(int nPane, HICON hIcon)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPane < 256);
+ return (BOOL)::SendMessage(m_hWnd, SB_SETICON, nPane, (LPARAM)hIcon);
+ }
+#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
+};
+
+typedef CStatusBarCtrlT<ATL::CWindow> CStatusBarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTabCtrl
+
+template <class TBase>
+class CTabCtrlT : public TBase
+{
+public:
+// Constructors
+ CTabCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CTabCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_TABCONTROL;
+ }
+
+ CImageList GetImageList() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_GETIMAGELIST, 0, 0L));
+ }
+
+ CImageList SetImageList(HIMAGELIST hImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)hImageList));
+ }
+
+ int GetItemCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_GETITEMCOUNT, 0, 0L);
+ }
+
+ BOOL GetItem(int nItem, LPTCITEM pTabCtrlItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_GETITEM, nItem, (LPARAM)pTabCtrlItem);
+ }
+
+ BOOL SetItem(int nItem, LPTCITEM pTabCtrlItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)pTabCtrlItem);
+ }
+
+ int SetItem(int nItem, UINT mask, LPCTSTR lpszItem, DWORD dwState, DWORD dwStateMask, int iImage, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TCITEM tci = { 0 };
+ tci.mask = mask;
+ tci.pszText = (LPTSTR) lpszItem;
+ tci.dwState = dwState;
+ tci.dwStateMask = dwStateMask;
+ tci.iImage = iImage;
+ tci.lParam = lParam;
+ return (int)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)&tci);
+ }
+
+ BOOL GetItemRect(int nItem, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_GETITEMRECT, nItem, (LPARAM)lpRect);
+ }
+
+ int GetCurSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0L);
+ }
+
+ int SetCurSel(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_SETCURSEL, nItem, 0L);
+ }
+
+ SIZE SetItemSize(SIZE size)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwSize = (DWORD)::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(size.cx, size.cy));
+ SIZE sizeRet = { GET_X_LPARAM(dwSize), GET_Y_LPARAM(dwSize) };
+ return sizeRet;
+ }
+
+ void SetItemSize(int cx, int cy)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(cx, cy));
+ }
+
+ void SetPadding(SIZE size)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_SETPADDING, 0, MAKELPARAM(size.cx, size.cy));
+ }
+
+ int GetRowCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_GETROWCOUNT, 0, 0L);
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetTooltips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TCM_GETTOOLTIPS, 0, 0L));
+ }
+
+ void SetTooltips(HWND hWndToolTip)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ int GetCurFocus() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_GETCURFOCUS, 0, 0L);
+ }
+
+ void SetCurFocus(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_SETCURFOCUS, nItem, 0L);
+ }
+
+ BOOL SetItemExtra(int cbExtra)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetItemCount() == 0); // must be empty
+ return (BOOL)::SendMessage(m_hWnd, TCM_SETITEMEXTRA, cbExtra, 0L);
+ }
+
+ int SetMinTabWidth(int nWidth = -1)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_SETMINTABWIDTH, 0, nWidth);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ DWORD GetExtendedStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TCM_GETEXTENDEDSTYLE, 0, 0L);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, TCM_SETEXTENDEDSTYLE, dwExMask, dwExStyle);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+// Operations
+ int InsertItem(int nItem, LPTCITEM pTabCtrlItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)pTabCtrlItem);
+ }
+
+ int InsertItem(int nItem, UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TCITEM tci = { 0 };
+ tci.mask = mask;
+ tci.pszText = (LPTSTR) lpszItem;
+ tci.iImage = iImage;
+ tci.lParam = lParam;
+ return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci);
+ }
+
+ int InsertItem(int nItem, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_TEXT;
+ tci.pszText = (LPTSTR) lpszItem;
+ return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci);
+ }
+
+ int AddItem(LPTCITEM pTabCtrlItem)
+ {
+ return InsertItem(GetItemCount(), pTabCtrlItem);
+ }
+
+ int AddItem(UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam)
+ {
+ return InsertItem(GetItemCount(), mask, lpszItem, iImage, lParam);
+ }
+
+ int AddItem(LPCTSTR lpszItem)
+ {
+ return InsertItem(GetItemCount(), lpszItem);
+ }
+
+ BOOL DeleteItem(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_DELETEITEM, nItem, 0L);
+ }
+
+ BOOL DeleteAllItems()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_DELETEALLITEMS, 0, 0L);
+ }
+
+ void AdjustRect(BOOL bLarger, LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect);
+ }
+
+ void RemoveImage(int nImage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_REMOVEIMAGE, nImage, 0L);
+ }
+
+ int HitTest(TC_HITTESTINFO* pHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo);
+ }
+
+ void DeselectAll(BOOL bExcludeFocus = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TCM_DESELECTALL, bExcludeFocus, 0L);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ BOOL HighlightItem(int nIndex, BOOL bHighlight = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TCM_HIGHLIGHTITEM, nIndex, MAKELPARAM(bHighlight, 0));
+ }
+#endif // (_WIN32_IE >= 0x0400)
+};
+
+typedef CTabCtrlT<ATL::CWindow> CTabCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTrackBarCtrl
+
+template <class TBase>
+class CTrackBarCtrlT : public TBase
+{
+public:
+// Constructors
+ CTrackBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CTrackBarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return TRACKBAR_CLASS;
+ }
+
+ int GetLineSize() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETLINESIZE, 0, 0L);
+ }
+
+ int SetLineSize(int nSize)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_SETLINESIZE, 0, nSize);
+ }
+
+ int GetPageSize() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETPAGESIZE, 0, 0L);
+ }
+
+ int SetPageSize(int nSize)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_SETPAGESIZE, 0, nSize);
+ }
+
+ int GetRangeMin() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETRANGEMIN, 0, 0L);
+ }
+
+ void SetRangeMin(int nMin, BOOL bRedraw = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin);
+ }
+
+ int GetRangeMax() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETRANGEMAX, 0, 0L);
+ }
+
+ void SetRangeMax(int nMax, BOOL bRedraw = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETRANGEMAX, bRedraw, nMax);
+ }
+
+ void GetRange(int& nMin, int& nMax) const
+ {
+ nMin = GetRangeMin();
+ nMax = GetRangeMax();
+ }
+
+ void SetRange(int nMin, int nMax, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETRANGE, bRedraw, MAKELPARAM(nMin, nMax));
+ }
+
+ int GetSelStart() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L);
+ }
+
+ void SetSelStart(int nMin)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETSELSTART, 0, (LPARAM)nMin);
+ }
+
+ int GetSelEnd() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L);
+ }
+
+ void SetSelEnd(int nMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETSELEND, 0, (LPARAM)nMax);
+ }
+
+ void GetSelection(int& nMin, int& nMax) const
+ {
+ nMin = GetSelStart();
+ nMax = GetSelEnd();
+ }
+
+ void SetSelection(int nMin, int nMax)
+ {
+ SetSelStart(nMin);
+ SetSelEnd(nMax);
+ }
+
+ void GetChannelRect(LPRECT lprc) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)lprc);
+ }
+
+ void GetThumbRect(LPRECT lprc) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)lprc);
+ }
+
+ int GetPos() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETPOS, 0, 0L);
+ }
+
+ void SetPos(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETPOS, TRUE, nPos);
+ }
+
+ UINT GetNumTics() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, TBM_GETNUMTICS, 0, 0L);
+ }
+
+ DWORD* GetTicArray() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD*)::SendMessage(m_hWnd, TBM_GETPTICS, 0, 0L);
+ }
+
+ int GetTic(int nTic) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETTIC, nTic, 0L);
+ }
+
+ BOOL SetTic(int nTic)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TBM_SETTIC, 0, nTic);
+ }
+
+ int GetTicPos(int nTic) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETTICPOS, nTic, 0L);
+ }
+
+ void SetTicFreq(int nFreq)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETTICFREQ, nFreq, 0L);
+ }
+
+ int GetThumbLength() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_GETTHUMBLENGTH, 0, 0L);
+ }
+
+ void SetThumbLength(int nLength)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETTHUMBLENGTH, nLength, 0L);
+ }
+
+ void SetSel(int nStart, int nEnd, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & TBS_ENABLESELRANGE) != 0);
+ ::SendMessage(m_hWnd, TBM_SETSEL, bRedraw, MAKELPARAM(nStart, nEnd));
+ }
+
+ ATL::CWindow GetBuddy(BOOL bLeft = TRUE) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_GETBUDDY, bLeft, 0L));
+ }
+
+ ATL::CWindow SetBuddy(HWND hWndBuddy, BOOL bLeft = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_SETBUDDY, bLeft, (LPARAM)hWndBuddy));
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetToolTips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TBM_GETTOOLTIPS, 0, 0L));
+ }
+
+ void SetToolTips(HWND hWndTT)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETTOOLTIPS, (WPARAM)hWndTT, 0L);
+ }
+
+ int SetTipSide(int nSide)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, TBM_SETTIPSIDE, nSide, 0L);
+ }
+#endif // !_WIN32_WCE
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TBM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, TBM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+// Operations
+ void ClearSel(BOOL bRedraw = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_CLEARSEL, bRedraw, 0L);
+ }
+
+ void VerifyPos()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_SETPOS, FALSE, 0L);
+ }
+
+ void ClearTics(BOOL bRedraw = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, TBM_CLEARTICS, bRedraw, 0L);
+ }
+};
+
+typedef CTrackBarCtrlT<ATL::CWindow> CTrackBarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CUpDownCtrl
+
+template <class TBase>
+class CUpDownCtrlT : public TBase
+{
+public:
+// Constructors
+ CUpDownCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CUpDownCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return UPDOWN_CLASS;
+ }
+
+ UINT GetAccel(int nAccel, UDACCEL* pAccel) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETACCEL, nAccel, (LPARAM)pAccel));
+ }
+
+ BOOL SetAccel(int nAccel, UDACCEL* pAccel)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)LOWORD(::SendMessage(m_hWnd, UDM_SETACCEL, nAccel, (LPARAM)pAccel));
+ }
+
+ UINT GetBase() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETBASE, 0, 0L));
+ }
+
+ int SetBase(int nBase)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, UDM_SETBASE, nBase, 0L);
+ }
+
+ ATL::CWindow GetBuddy() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0L));
+ }
+
+ ATL::CWindow SetBuddy(HWND hWndBuddy)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_SETBUDDY, (WPARAM)hWndBuddy, 0L));
+ }
+
+ int GetPos(LPBOOL lpbError = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETPOS, 0, 0L);
+ // Note: Seems that Windows always sets error to TRUE if
+ // UDS_SETBUDDYINT style is not used
+ if(lpbError != NULL)
+ *lpbError = (HIWORD(dwRet) != 0) ? TRUE : FALSE;
+ return (int)(short)LOWORD(dwRet);
+ }
+
+ int SetPos(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)(short)LOWORD(::SendMessage(m_hWnd, UDM_SETPOS, 0, MAKELPARAM(nPos, 0)));
+ }
+
+ DWORD GetRange() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L);
+ }
+
+ void GetRange(int& nLower, int& nUpper) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L);
+ nLower = (int)(short)HIWORD(dwRet);
+ nUpper = (int)(short)LOWORD(dwRet);
+ }
+
+ void SetRange(int nLower, int nUpper)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower));
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ void SetRange32(int nLower, int nUpper)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, UDM_SETRANGE32, nLower, nUpper);
+ }
+
+ void GetRange32(int& nLower, int& nUpper) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, UDM_GETRANGE32, (WPARAM)&nLower, (LPARAM)&nUpper);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, UDM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, UDM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ int GetPos32(LPBOOL lpbError = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ // Note: Seems that Windows always sets error to TRUE if
+ // UDS_SETBUDDYINT style is not used
+ return (int)::SendMessage(m_hWnd, UDM_GETPOS32, 0, (LPARAM)lpbError);
+ }
+
+ int SetPos32(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, UDM_SETPOS32, 0, (LPARAM)nPos);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+};
+
+typedef CUpDownCtrlT<ATL::CWindow> CUpDownCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CProgressBarCtrl
+
+template <class TBase>
+class CProgressBarCtrlT : public TBase
+{
+public:
+// Constructors
+ CProgressBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CProgressBarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return PROGRESS_CLASS;
+ }
+
+ DWORD SetRange(int nLower, int nUpper)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper));
+ }
+
+ int SetPos(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L));
+ }
+
+ int OffsetPos(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_DELTAPOS, nPos, 0L));
+ }
+
+ int SetStep(int nStep)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETSTEP, nStep, 0L));
+ }
+
+ UINT GetPos() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, PBM_GETPOS, 0, 0L);
+ }
+
+ void GetRange(PPBRANGE pPBRange) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pPBRange != NULL);
+ ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)pPBRange);
+ }
+
+ void GetRange(int& nLower, int& nUpper) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ PBRANGE range = { 0 };
+ ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)&range);
+ nLower = range.iLow;
+ nUpper = range.iHigh;
+ }
+
+ int GetRangeLimit(BOOL bLowLimit) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PBM_GETRANGE, bLowLimit, (LPARAM)NULL);
+ }
+
+ DWORD SetRange32(int nMin, int nMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE32, nMin, nMax);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ COLORREF SetBarColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PBM_SETBARCOLOR, 0, (LPARAM)clr);
+ }
+
+ COLORREF SetBkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PBM_SETBKCOLOR, 0, (LPARAM)clr);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE)
+ BOOL SetMarquee(BOOL bMarquee, UINT uUpdateTime = 0U)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PBM_SETMARQUEE, (WPARAM)bMarquee, (LPARAM)uUpdateTime);
+ }
+#endif // (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE)
+
+#if (_WIN32_WINNT >= 0x0600)
+ int GetStep() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PBM_GETSTEP, 0, 0L);
+ }
+
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PBM_GETBKCOLOR, 0, 0L);
+ }
+
+ COLORREF GetBarColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PBM_GETBARCOLOR, 0, 0L);
+ }
+
+ int GetState() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PBM_GETSTATE, 0, 0L);
+ }
+
+ int SetState(int nState)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PBM_SETSTATE, nState, 0L);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+// Operations
+ int StepIt()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_STEPIT, 0, 0L));
+ }
+};
+
+typedef CProgressBarCtrlT<ATL::CWindow> CProgressBarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CHotKeyCtrl
+
+#ifndef _WIN32_WCE
+
+template <class TBase>
+class CHotKeyCtrlT : public TBase
+{
+public:
+// Constructors
+ CHotKeyCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CHotKeyCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return HOTKEY_CLASS;
+ }
+
+ DWORD GetHotKey() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L);
+ }
+
+ void GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dw = (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L);
+ wVirtualKeyCode = LOBYTE(LOWORD(dw));
+ wModifiers = HIBYTE(LOWORD(dw));
+ }
+
+ void SetHotKey(WORD wVirtualKeyCode, WORD wModifiers)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, HKM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0L);
+ }
+
+ void SetRules(WORD wInvalidComb, WORD wModifiers)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, HKM_SETRULES, wInvalidComb, MAKELPARAM(wModifiers, 0));
+ }
+};
+
+typedef CHotKeyCtrlT<ATL::CWindow> CHotKeyCtrl;
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAnimateCtrl
+
+#ifndef _WIN32_WCE
+
+template <class TBase>
+class CAnimateCtrlT : public TBase
+{
+public:
+// Constructors
+ CAnimateCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CAnimateCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return ANIMATE_CLASS;
+ }
+
+// Operations
+ BOOL Open(ATL::_U_STRINGorID FileName)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, (LPARAM)FileName.m_lpstr);
+ }
+
+ BOOL Play(UINT nFrom, UINT nTo, UINT nRep)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, nRep, MAKELPARAM(nFrom, nTo));
+ }
+
+ BOOL Stop()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_STOP, 0, 0L);
+ }
+
+ BOOL Close()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, 0L);
+ }
+
+ BOOL Seek(UINT nTo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, 0, MAKELPARAM(nTo, nTo));
+ }
+
+ // Vista only
+ BOOL IsPlaying() const
+ {
+#ifndef ACM_ISPLAYING
+ const UINT ACM_ISPLAYING = (WM_USER+104);
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, ACM_ISPLAYING, 0, 0L);
+ }
+};
+
+typedef CAnimateCtrlT<ATL::CWindow> CAnimateCtrl;
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRichEditCtrl
+
+#ifndef _WIN32_WCE
+
+#ifdef _UNICODE
+#if (_RICHEDIT_VER == 0x0100)
+#undef RICHEDIT_CLASS
+#define RICHEDIT_CLASS L"RICHEDIT"
+#endif // (_RICHEDIT_VER == 0x0100)
+#endif // _UNICODE
+
+template <class TBase>
+class CRichEditCtrlT : public TBase
+{
+public:
+// Constructors
+ CRichEditCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CRichEditCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return RICHEDIT_CLASS;
+ }
+
+ static LPCTSTR GetLibraryName()
+ {
+#if (_RICHEDIT_VER >= 0x0200)
+ return _T("RICHED20.DLL");
+#else
+ return _T("RICHED32.DLL");
+#endif
+ }
+
+ int GetLineCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L);
+ }
+
+ BOOL GetModify() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);
+ }
+
+ void SetModify(BOOL bModified = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L);
+ }
+
+ void GetRect(LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect);
+ }
+
+ DWORD GetOptions() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_GETOPTIONS, 0, 0L);
+ }
+
+ DWORD SetOptions(WORD wOperation, DWORD dwOptions)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_SETOPTIONS, wOperation, dwOptions);
+ }
+
+ // NOTE: first word in lpszBuffer must contain the size of the buffer!
+ int GetLine(int nIndex, LPTSTR lpszBuffer) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
+ }
+
+ int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ *(LPWORD)lpszBuffer = (WORD)nMaxLength;
+ return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
+ }
+
+ BOOL CanUndo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);
+ }
+
+ BOOL CanPaste(UINT nFormat = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, nFormat, 0L);
+ }
+
+ void GetSel(LONG& nStartChar, LONG& nEndChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ CHARRANGE cr = { 0, 0 };
+ ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
+ nStartChar = cr.cpMin;
+ nEndChar = cr.cpMax;
+ }
+
+ void GetSel(CHARRANGE &cr) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
+ }
+
+ int SetSel(LONG nStartChar, LONG nEndChar)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ CHARRANGE cr = { nStartChar, nEndChar };
+ return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr);
+ }
+
+ int SetSel(CHARRANGE &cr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr);
+ }
+
+ int SetSelAll()
+ {
+ return SetSel(0, -1);
+ }
+
+ int SetSelNone()
+ {
+ return SetSel(-1, 0);
+ }
+
+ DWORD GetDefaultCharFormat(CHARFORMAT& cf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf);
+ }
+
+ DWORD GetSelectionCharFormat(CHARFORMAT& cf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf);
+ }
+
+ DWORD GetEventMask() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_GETEVENTMASK, 0, 0L);
+ }
+
+ LONG GetLimitText() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L);
+ }
+
+ DWORD GetParaFormat(PARAFORMAT& pf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ pf.cbSize = sizeof(PARAFORMAT);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
+ }
+
+#if (_RICHEDIT_VER >= 0x0200)
+ LONG GetSelText(LPTSTR lpstrBuff) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff);
+ }
+#else // !(_RICHEDIT_VER >= 0x0200)
+ // RichEdit 1.0 EM_GETSELTEXT is ANSI only
+ LONG GetSelText(LPSTR lpstrBuff) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff);
+ }
+#endif // !(_RICHEDIT_VER >= 0x0200)
+
+#ifndef _ATL_NO_COM
+ BOOL GetSelTextBSTR(BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+
+ CHARRANGE cr = { 0, 0 };
+ ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
+
+#if (_RICHEDIT_VER >= 0x0200)
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);
+ if(lpstrText == NULL)
+ return FALSE;
+ if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0)
+ return FALSE;
+
+ bstrText = ::SysAllocString(T2W(lpstrText));
+#else // !(_RICHEDIT_VER >= 0x0200)
+ CTempBuffer<char, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);
+ if(lpstrText == NULL)
+ return FALSE;
+ if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0)
+ return FALSE;
+
+ bstrText = ::SysAllocString(A2W(lpstrText));
+#endif // !(_RICHEDIT_VER >= 0x0200)
+
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ LONG GetSelText(_CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ CHARRANGE cr = { 0, 0 };
+ ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
+
+#if (_RICHEDIT_VER >= 0x0200)
+ LONG lLen = 0;
+ LPTSTR lpstrText = strText.GetBufferSetLength(cr.cpMax - cr.cpMin);
+ if(lpstrText != NULL)
+ {
+ lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText);
+ strText.ReleaseBuffer();
+ }
+#else // !(_RICHEDIT_VER >= 0x0200)
+ CTempBuffer<char, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);
+ if(lpstrText == NULL)
+ return 0;
+ LONG lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText);
+ if(lLen == 0)
+ return 0;
+
+ USES_CONVERSION;
+ strText = A2T(lpstrText);
+#endif // !(_RICHEDIT_VER >= 0x0200)
+
+ return lLen;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ WORD GetSelectionType() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (WORD)::SendMessage(m_hWnd, EM_SELECTIONTYPE, 0, 0L);
+ }
+
+ COLORREF SetBackgroundColor(COLORREF cr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 0, cr);
+ }
+
+ COLORREF SetBackgroundColor() // sets to system background
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 1, 0);
+ }
+
+ BOOL SetCharFormat(CHARFORMAT& cf, WORD wFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf);
+ }
+
+ BOOL SetDefaultCharFormat(CHARFORMAT& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf);
+ }
+
+ BOOL SetSelectionCharFormat(CHARFORMAT& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+
+ BOOL SetWordCharFormat(CHARFORMAT& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf);
+ }
+
+ DWORD SetEventMask(DWORD dwEventMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_SETEVENTMASK, 0, dwEventMask);
+ }
+
+ BOOL SetParaFormat(PARAFORMAT& pf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ pf.cbSize = sizeof(PARAFORMAT);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
+ }
+
+ BOOL SetTargetDevice(HDC hDC, int cxLineWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTARGETDEVICE, (WPARAM)hDC, cxLineWidth);
+ }
+
+ int GetTextLength() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L);
+ }
+
+ BOOL SetReadOnly(BOOL bReadOnly = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L);
+ }
+
+ int GetFirstVisibleLine() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);
+ }
+
+ EDITWORDBREAKPROCEX GetWordBreakProcEx() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_GETWORDBREAKPROCEX, 0, 0L);
+ }
+
+ EDITWORDBREAKPROCEX SetWordBreakProcEx(EDITWORDBREAKPROCEX pfnEditWordBreakProcEx)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_SETWORDBREAKPROCEX, 0, (LPARAM)pfnEditWordBreakProcEx);
+ }
+
+ int GetTextRange(TEXTRANGE* pTextRange) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)pTextRange);
+ }
+
+#if (_RICHEDIT_VER >= 0x0200)
+ int GetTextRange(LONG nStartChar, LONG nEndChar, LPTSTR lpstrText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TEXTRANGE tr = { 0 };
+ tr.chrg.cpMin = nStartChar;
+ tr.chrg.cpMax = nEndChar;
+ tr.lpstrText = lpstrText;
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ }
+#else // !(_RICHEDIT_VER >= 0x0200)
+
+ int GetTextRange(LONG nStartChar, LONG nEndChar, LPSTR lpstrText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ TEXTRANGE tr = { 0 };
+ tr.chrg.cpMin = nStartChar;
+ tr.chrg.cpMax = nEndChar;
+ tr.lpstrText = lpstrText;
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ }
+#endif // !(_RICHEDIT_VER >= 0x0200)
+
+#if (_RICHEDIT_VER >= 0x0200)
+ DWORD GetDefaultCharFormat(CHARFORMAT2& cf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf);
+ }
+
+ BOOL SetCharFormat(CHARFORMAT2& cf, WORD wFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf);
+ }
+
+ BOOL SetDefaultCharFormat(CHARFORMAT2& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf);
+ }
+
+ DWORD GetSelectionCharFormat(CHARFORMAT2& cf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf);
+ }
+
+ BOOL SetSelectionCharFormat(CHARFORMAT2& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+
+ BOOL SetWordCharFormat(CHARFORMAT2& cf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf);
+ }
+
+ DWORD GetParaFormat(PARAFORMAT2& pf) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ pf.cbSize = sizeof(PARAFORMAT2);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
+ }
+
+ BOOL SetParaFormat(PARAFORMAT2& pf)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ pf.cbSize = sizeof(PARAFORMAT2);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
+ }
+
+ TEXTMODE GetTextMode() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (TEXTMODE)::SendMessage(m_hWnd, EM_GETTEXTMODE, 0, 0L);
+ }
+
+ BOOL SetTextMode(TEXTMODE enumTextMode)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return !(BOOL)::SendMessage(m_hWnd, EM_SETTEXTMODE, enumTextMode, 0L);
+ }
+
+ UNDONAMEID GetUndoName() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETUNDONAME, 0, 0L);
+ }
+
+ UNDONAMEID GetRedoName() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETREDONAME, 0, 0L);
+ }
+
+ BOOL CanRedo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L);
+ }
+
+ BOOL GetAutoURLDetect() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETAUTOURLDETECT, 0, 0L);
+ }
+
+ BOOL SetAutoURLDetect(BOOL bAutoDetect = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return !(BOOL)::SendMessage(m_hWnd, EM_AUTOURLDETECT, bAutoDetect, 0L);
+ }
+
+ // this method is deprecated, please use SetAutoURLDetect
+ BOOL EnableAutoURLDetect(BOOL bEnable = TRUE) { return SetAutoURLDetect(bEnable); }
+
+ UINT SetUndoLimit(UINT uUndoLimit)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_SETUNDOLIMIT, uUndoLimit, 0L);
+ }
+
+ void SetPalette(HPALETTE hPalette)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETPALETTE, (WPARAM)hPalette, 0L);
+ }
+
+ int GetTextEx(GETTEXTEX* pGetTextEx, LPTSTR lpstrText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)pGetTextEx, (LPARAM)lpstrText);
+ }
+
+ int GetTextEx(LPTSTR lpstrText, int nTextLen, DWORD dwFlags = GT_DEFAULT, UINT uCodePage = CP_ACP, LPCSTR lpDefaultChar = NULL, LPBOOL lpUsedDefChar = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ GETTEXTEX gte = { 0 };
+ gte.cb = nTextLen * sizeof(TCHAR);
+ gte.codepage = uCodePage;
+ gte.flags = dwFlags;
+ gte.lpDefaultChar = lpDefaultChar;
+ gte.lpUsedDefChar = lpUsedDefChar;
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)>e, (LPARAM)lpstrText);
+ }
+
+ int GetTextLengthEx(GETTEXTLENGTHEX* pGetTextLengthEx) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)pGetTextLengthEx, 0L);
+ }
+
+ int GetTextLengthEx(DWORD dwFlags = GTL_DEFAULT, UINT uCodePage = CP_ACP) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ GETTEXTLENGTHEX gtle = { 0 };
+ gtle.codepage = uCodePage;
+ gtle.flags = dwFlags;
+ return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)>le, 0L);
+ }
+#endif // (_RICHEDIT_VER >= 0x0200)
+
+#if (_RICHEDIT_VER >= 0x0300)
+ int SetTextEx(SETTEXTEX* pSetTextEx, LPCTSTR lpstrText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)pSetTextEx, (LPARAM)lpstrText);
+ }
+
+ int SetTextEx(LPCTSTR lpstrText, DWORD dwFlags = ST_DEFAULT, UINT uCodePage = CP_ACP)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ SETTEXTEX ste = { 0 };
+ ste.flags = dwFlags;
+ ste.codepage = uCodePage;
+ return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpstrText);
+ }
+
+ int GetEditStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_GETEDITSTYLE, 0, 0L);
+ }
+
+ int SetEditStyle(int nStyle, int nMask = -1)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ if(nMask == -1)
+ nMask = nStyle; // set everything specified
+ return (int)::SendMessage(m_hWnd, EM_SETEDITSTYLE, nStyle, nMask);
+ }
+
+ BOOL SetFontSize(int nFontSizeDelta)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nFontSizeDelta >= -1637 && nFontSizeDelta <= 1638);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETFONTSIZE, nFontSizeDelta, 0L);
+ }
+
+ void GetScrollPos(LPPOINT lpPoint) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpPoint != NULL);
+ ::SendMessage(m_hWnd, EM_GETSCROLLPOS, 0, (LPARAM)lpPoint);
+ }
+
+ void SetScrollPos(LPPOINT lpPoint)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpPoint != NULL);
+ ::SendMessage(m_hWnd, EM_SETSCROLLPOS, 0, (LPARAM)lpPoint);
+ }
+
+ BOOL GetZoom(int& nNum, int& nDen) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETZOOM, (WPARAM)&nNum, (LPARAM)&nDen);
+ }
+
+ BOOL SetZoom(int nNum, int nDen)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nNum >= 0 && nNum <= 64);
+ ATLASSERT(nDen >= 0 && nDen <= 64);
+ return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, nNum, nDen);
+ }
+
+ BOOL SetZoomOff()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, 0, 0L);
+ }
+#endif // (_RICHEDIT_VER >= 0x0300)
+
+// Operations
+ void LimitText(LONG nChars = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_EXLIMITTEXT, 0, nChars);
+ }
+
+ int LineFromChar(LONG nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nIndex);
+ }
+
+ POINT PosFromChar(LONG nChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ POINT point = { 0, 0 };
+ ::SendMessage(m_hWnd, EM_POSFROMCHAR, (WPARAM)&point, nChar);
+ return point;
+ }
+
+ int CharFromPos(POINT pt) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ POINTL ptl = { pt.x, pt.y };
+ return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&ptl);
+ }
+
+ void EmptyUndoBuffer()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L);
+ }
+
+ int LineIndex(int nLine = -1) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L);
+ }
+
+ int LineLength(int nLine = -1) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L);
+ }
+
+ BOOL LineScroll(int nLines, int nChars = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines);
+ }
+
+ void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText);
+ }
+
+ void SetRect(LPCRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect);
+ }
+
+ BOOL DisplayBand(LPRECT pDisplayRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_DISPLAYBAND, 0, (LPARAM)pDisplayRect);
+ }
+
+ LONG FindText(DWORD dwFlags, FINDTEXT& ft) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE)
+ return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTW, dwFlags, (LPARAM)&ft);
+#else
+ return (LONG)::SendMessage(m_hWnd, EM_FINDTEXT, dwFlags, (LPARAM)&ft);
+#endif
+ }
+
+ LONG FindText(DWORD dwFlags, FINDTEXTEX& ft) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE)
+ return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEXW, dwFlags, (LPARAM)&ft);
+#else
+ return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&ft);
+#endif
+ }
+
+ LONG FormatRange(FORMATRANGE& fr, BOOL bDisplay = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)&fr);
+ }
+
+ LONG FormatRange(FORMATRANGE* pFormatRange, BOOL bDisplay = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)pFormatRange);
+ }
+
+ void HideSelection(BOOL bHide = TRUE, BOOL bChangeStyle = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_HIDESELECTION, bHide, bChangeStyle);
+ }
+
+ void PasteSpecial(UINT uClipFormat, DWORD dwAspect = 0, HMETAFILE hMF = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ REPASTESPECIAL reps = { dwAspect, (DWORD_PTR)hMF };
+ ::SendMessage(m_hWnd, EM_PASTESPECIAL, uClipFormat, (LPARAM)&reps);
+ }
+
+ void RequestResize()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_REQUESTRESIZE, 0, 0L);
+ }
+
+ LONG StreamIn(UINT uFormat, EDITSTREAM& es)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, uFormat, (LPARAM)&es);
+ }
+
+ LONG StreamOut(UINT uFormat, EDITSTREAM& es)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, uFormat, (LPARAM)&es);
+ }
+
+ DWORD FindWordBreak(int nCode, LONG nStartChar)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, EM_FINDWORDBREAK, nCode, nStartChar);
+ }
+
+ // Additional operations
+ void ScrollCaret()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);
+ }
+
+ int InsertText(long nInsertAfterChar, LPCTSTR lpstrText, BOOL bCanUndo = FALSE)
+ {
+ int nRet = SetSel(nInsertAfterChar, nInsertAfterChar);
+ ReplaceSel(lpstrText, bCanUndo);
+ return nRet;
+ }
+
+ int AppendText(LPCTSTR lpstrText, BOOL bCanUndo = FALSE)
+ {
+ return InsertText(GetWindowTextLength(), lpstrText, bCanUndo);
+ }
+
+ // Clipboard operations
+ BOOL Undo()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L);
+ }
+
+ void Clear()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);
+ }
+
+ void Copy()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_COPY, 0, 0L);
+ }
+
+ void Cut()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CUT, 0, 0L);
+ }
+
+ void Paste()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_PASTE, 0, 0L);
+ }
+
+ // OLE support
+ IRichEditOle* GetOleInterface() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ IRichEditOle *pRichEditOle = NULL;
+ ::SendMessage(m_hWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);
+ return pRichEditOle;
+ }
+
+ BOOL SetOleCallback(IRichEditOleCallback* pCallback)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETOLECALLBACK, 0, (LPARAM)pCallback);
+ }
+
+#if (_RICHEDIT_VER >= 0x0200)
+ BOOL Redo()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_REDO, 0, 0L);
+ }
+
+ void StopGroupTyping()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_STOPGROUPTYPING, 0, 0L);
+ }
+
+ void ShowScrollBar(int nBarType, BOOL bVisible = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SHOWSCROLLBAR, nBarType, bVisible);
+ }
+#endif // (_RICHEDIT_VER >= 0x0200)
+
+#if (_RICHEDIT_VER >= 0x0300)
+ BOOL SetTabStops(int nTabStops, LPINT rgTabStops)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);
+ }
+
+ BOOL SetTabStops()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L);
+ }
+
+ BOOL SetTabStops(const int& cxEachStop) // takes an 'int'
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);
+ }
+#endif // (_RICHEDIT_VER >= 0x0300)
+};
+
+typedef CRichEditCtrlT<ATL::CWindow> CRichEditCtrl;
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRichEditCommands - message handlers for standard EDIT commands
+
+#ifndef _WIN32_WCE
+
+// Chain to CRichEditCommands message map. Your class must also derive from CRichEditCtrl.
+// Example:
+// class CMyRichEdit : public CWindowImpl<CMyRichEdit, CRichEditCtrl>,
+// public CRichEditCommands<CMyRichEdit>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyRichEdit)
+// // your handlers...
+// CHAIN_MSG_MAP_ALT(CRichEditCommands<CMyRichEdit>, 1)
+// END_MSG_MAP()
+// // other stuff...
+// };
+
+template <class T>
+class CRichEditCommands : public CEditCommands< T >
+{
+public:
+ BEGIN_MSG_MAP(CRichEditCommands< T >)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_EDIT_CLEAR, CEditCommands< T >::OnEditClear)
+ COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, CEditCommands< T >::OnEditClearAll)
+ COMMAND_ID_HANDLER(ID_EDIT_COPY, CEditCommands< T >::OnEditCopy)
+ COMMAND_ID_HANDLER(ID_EDIT_CUT, CEditCommands< T >::OnEditCut)
+ COMMAND_ID_HANDLER(ID_EDIT_PASTE, CEditCommands< T >::OnEditPaste)
+ COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, CEditCommands< T >::OnEditSelectAll)
+ COMMAND_ID_HANDLER(ID_EDIT_UNDO, CEditCommands< T >::OnEditUndo)
+#if (_RICHEDIT_VER >= 0x0200)
+ COMMAND_ID_HANDLER(ID_EDIT_REDO, OnEditRedo)
+#endif // (_RICHEDIT_VER >= 0x0200)
+ END_MSG_MAP()
+
+#if (_RICHEDIT_VER >= 0x0200)
+ LRESULT OnEditRedo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Redo();
+ return 0;
+ }
+#endif // (_RICHEDIT_VER >= 0x0200)
+
+// State (update UI) helpers
+ BOOL CanCut() const
+ { return HasSelection(); }
+
+ BOOL CanCopy() const
+ { return HasSelection(); }
+
+ BOOL CanClear() const
+ { return HasSelection(); }
+
+// Implementation
+ BOOL HasSelection() const
+ {
+ const T* pT = static_cast<const T*>(this);
+ return (pT->GetSelectionType() != SEL_EMPTY);
+ }
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDragListBox
+
+#ifndef _WIN32_WCE
+
+template <class TBase>
+class CDragListBoxT : public CListBoxT< TBase >
+{
+public:
+// Constructors
+ CDragListBoxT(HWND hWnd = NULL) : CListBoxT< TBase >(hWnd)
+ { }
+
+ CDragListBoxT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ if(hWnd != NULL)
+ MakeDragList();
+ return hWnd;
+ }
+
+// Operations
+ BOOL MakeDragList()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);
+ return ::MakeDragList(m_hWnd);
+ }
+
+ int LBItemFromPt(POINT pt, BOOL bAutoScroll = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::LBItemFromPt(m_hWnd, pt, bAutoScroll);
+ }
+
+ void DrawInsert(int nItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::DrawInsert(GetParent(), m_hWnd, nItem);
+ }
+
+ static UINT GetDragListMessage()
+ {
+ static UINT uDragListMessage = 0;
+ if(uDragListMessage == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDragListBox::GetDragListMessage.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uDragListMessage == 0)
+ uDragListMessage = ::RegisterWindowMessage(DRAGLISTMSGSTRING);
+
+ lock.Unlock();
+ }
+ ATLASSERT(uDragListMessage != 0);
+ return uDragListMessage;
+ }
+};
+
+typedef CDragListBoxT<ATL::CWindow> CDragListBox;
+
+template <class T>
+class CDragListNotifyImpl
+{
+public:
+ BEGIN_MSG_MAP(CDragListNotifyImpl< T >)
+ MESSAGE_HANDLER(CDragListBox::GetDragListMessage(), OnDragListNotify)
+ END_MSG_MAP()
+
+ LRESULT OnDragListNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ uMsg; // avoid level 4 warning
+ ATLASSERT(uMsg == CDragListBox::GetDragListMessage());
+ T* pT = static_cast<T*>(this);
+ LPDRAGLISTINFO lpDragListInfo = (LPDRAGLISTINFO)lParam;
+ LRESULT lRet = 0;
+ switch(lpDragListInfo->uNotification)
+ {
+ case DL_BEGINDRAG:
+ lRet = (LPARAM)pT->OnBeginDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);
+ break;
+ case DL_CANCELDRAG:
+ pT->OnCancelDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);
+ break;
+ case DL_DRAGGING:
+ lRet = (LPARAM)pT->OnDragging((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);
+ break;
+ case DL_DROPPED:
+ pT->OnDropped((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);
+ break;
+ default:
+ ATLTRACE2(atlTraceUI, 0, _T("Unknown DragListBox notification\n"));
+ bHandled = FALSE; // don't handle it
+ break;
+ }
+ return lRet;
+ }
+
+// Overrideables
+ BOOL OnBeginDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)
+ {
+ return TRUE; // allow dragging
+ }
+
+ void OnCancelDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)
+ {
+ // nothing to do
+ }
+
+ int OnDragging(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)
+ {
+ return 0; // don't change cursor
+ }
+
+ void OnDropped(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)
+ {
+ // nothing to do
+ }
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CReBarCtrl
+
+template <class TBase>
+class CReBarCtrlT : public TBase
+{
+public:
+// Constructors
+ CReBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CReBarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return REBARCLASSNAME;
+ }
+
+ UINT GetBandCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, RB_GETBANDCOUNT, 0, 0L);
+ }
+
+ BOOL GetBandInfo(int nBand, LPREBARBANDINFO lprbbi) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_GETBANDINFO, nBand, (LPARAM)lprbbi);
+ }
+
+ BOOL SetBandInfo(int nBand, LPREBARBANDINFO lprbbi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SETBANDINFO, nBand, (LPARAM)lprbbi);
+ }
+
+ BOOL GetBarInfo(LPREBARINFO lprbi) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)lprbi);
+ }
+
+ BOOL SetBarInfo(LPREBARINFO lprbi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)lprbi);
+ }
+
+ CImageList GetImageList() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ REBARINFO rbi = { 0 };
+ rbi.cbSize = sizeof(REBARINFO);
+ rbi.fMask = RBIM_IMAGELIST;
+ if( (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)&rbi) == FALSE ) return CImageList();
+ return CImageList(rbi.himl);
+ }
+
+ BOOL SetImageList(HIMAGELIST hImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ REBARINFO rbi = { 0 };
+ rbi.cbSize = sizeof(REBARINFO);
+ rbi.fMask = RBIM_IMAGELIST;
+ rbi.himl = hImageList;
+ return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)&rbi);
+ }
+
+ UINT GetRowCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, RB_GETROWCOUNT, 0, 0L);
+ }
+
+ UINT GetRowHeight(int nBand) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, RB_GETROWHEIGHT, nBand, 0L);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ COLORREF GetTextColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, RB_GETTEXTCOLOR, 0, 0L);
+ }
+
+ COLORREF SetTextColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, RB_SETTEXTCOLOR, 0, (LPARAM)clr);
+ }
+
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, RB_GETBKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetBkColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, RB_SETBKCOLOR, 0, (LPARAM)clr);
+ }
+
+ UINT GetBarHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, RB_GETBARHEIGHT, 0, 0L);
+ }
+
+ BOOL GetRect(int nBand, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_GETRECT, nBand, (LPARAM)lpRect);
+ }
+
+#ifndef _WIN32_WCE
+ CToolTipCtrl GetToolTips() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CToolTipCtrl((HWND)::SendMessage(m_hWnd, RB_GETTOOLTIPS, 0, 0L));
+ }
+
+ void SetToolTips(HWND hwndToolTip)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_SETTOOLTIPS, (WPARAM)hwndToolTip, 0L);
+ }
+#endif // !_WIN32_WCE
+
+ void GetBandBorders(int nBand, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpRect != NULL);
+ ::SendMessage(m_hWnd, RB_GETBANDBORDERS, nBand, (LPARAM)lpRect);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetColorScheme(LPCOLORSCHEME lpColorScheme) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpColorScheme != NULL);
+ return (BOOL)::SendMessage(m_hWnd, RB_GETCOLORSCHEME, 0, (LPARAM)lpColorScheme);
+ }
+
+ void SetColorScheme(LPCOLORSCHEME lpColorScheme)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpColorScheme != NULL);
+ ::SendMessage(m_hWnd, RB_SETCOLORSCHEME, 0, (LPARAM)lpColorScheme);
+ }
+
+ HPALETTE GetPalette() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HPALETTE)::SendMessage(m_hWnd, RB_GETPALETTE, 0, 0L);
+ }
+
+ HPALETTE SetPalette(HPALETTE hPalette)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HPALETTE)::SendMessage(m_hWnd, RB_SETPALETTE, 0, (LPARAM)hPalette);
+ }
+
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_WINNT >= 0x0501)
+ // requires uxtheme.h to be included to use MARGINS struct
+#ifndef _UXTHEME_H_
+ typedef struct _MARGINS* PMARGINS;
+#endif // !_UXTHEME_H_
+ void GetBandMargins(PMARGINS pMargins) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_GETBANDMARGINS, 0, (LPARAM)pMargins);
+ }
+
+ void SetWindowTheme(LPCWSTR lpstrTheme)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+#if (_WIN32_IE >= 0x0600)
+ DWORD GetExtendedStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, RB_GETEXTENDEDSTYLE, 0, 0L);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, RB_SETEXTENDEDSTYLE, dwMask, dwStyle);
+ }
+#endif // (_WIN32_IE >= 0x0600)
+
+// Operations
+ BOOL InsertBand(int nBand, LPREBARBANDINFO lprbbi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_INSERTBAND, nBand, (LPARAM)lprbbi);
+ }
+
+ BOOL AddBand(LPREBARBANDINFO lprbbi)
+ {
+ return InsertBand(-1, lprbbi);
+ }
+
+ BOOL DeleteBand(int nBand)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_DELETEBAND, nBand, 0L);
+ }
+
+ ATL::CWindow SetNotifyWnd(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow((HWND)::SendMessage(m_hWnd, RB_SETPARENT, (WPARAM)hWnd, 0L));
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ void BeginDrag(int nBand, DWORD dwPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, dwPos);
+ }
+
+ void BeginDrag(int nBand, int xPos, int yPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, MAKELPARAM(xPos, yPos));
+ }
+
+ void EndDrag()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_ENDDRAG, 0, 0L);
+ }
+
+ void DragMove(DWORD dwPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, dwPos);
+ }
+
+ void DragMove(int xPos, int yPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, MAKELPARAM(xPos, yPos));
+ }
+
+#ifndef _WIN32_WCE
+ void GetDropTarget(IDropTarget** ppDropTarget) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_GETDROPTARGET, 0, (LPARAM)ppDropTarget);
+ }
+#endif // !_WIN32_WCE
+
+ void MaximizeBand(int nBand, BOOL bIdeal = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_MAXIMIZEBAND, nBand, bIdeal);
+ }
+
+ void MinimizeBand(int nBand)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_MINIMIZEBAND, nBand, 0L);
+ }
+
+ BOOL SizeToRect(LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SIZETORECT, 0, (LPARAM)lpRect);
+ }
+
+ int IdToIndex(UINT uBandID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, RB_IDTOINDEX, uBandID, 0L);
+ }
+
+ int HitTest(LPRBHITTESTINFO lprbht) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, RB_HITTEST, 0, (LPARAM)lprbht);
+ }
+
+ BOOL ShowBand(int nBand, BOOL bShow)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SHOWBAND, nBand, bShow);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL MoveBand(int nBand, int nNewPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nNewPos >= 0 && nNewPos <= ((int)GetBandCount() - 1));
+ return (BOOL)::SendMessage(m_hWnd, RB_MOVEBAND, nBand, nNewPos);
+ }
+#endif // !_WIN32_WCE
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ void PushChevron(int nBand, LPARAM lAppValue)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, RB_PUSHCHEVRON, nBand, lAppValue);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+// Extra operations
+#if (_WIN32_IE >= 0x0400)
+ void LockBands(bool bLock)
+ {
+ int nBandCount = GetBandCount();
+ for(int i =0; i < nBandCount; i++)
+ {
+ REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };
+ rbbi.fMask = RBBIM_STYLE;
+ BOOL bRet = GetBandInfo(i, &rbbi);
+ ATLASSERT(bRet);
+
+ if((rbbi.fStyle & RBBS_GRIPPERALWAYS) == 0)
+ {
+ rbbi.fStyle |= RBBS_GRIPPERALWAYS;
+ bRet = SetBandInfo(i, &rbbi);
+ ATLASSERT(bRet);
+ rbbi.fStyle &= ~RBBS_GRIPPERALWAYS;
+ }
+
+ if(bLock)
+ rbbi.fStyle |= RBBS_NOGRIPPER;
+ else
+ rbbi.fStyle &= ~RBBS_NOGRIPPER;
+
+ bRet = SetBandInfo(i, &rbbi);
+ ATLASSERT(bRet);
+ }
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_WINNT >= 0x0600)
+ BOOL SetBandWidth(int nBand, int cxWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, RB_SETBANDWIDTH, nBand, cxWidth);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+};
+
+typedef CReBarCtrlT<ATL::CWindow> CReBarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CComboBoxEx
+
+#ifndef _WIN32_WCE
+
+template <class TBase>
+class CComboBoxExT : public CComboBoxT< TBase >
+{
+public:
+// Constructors
+ CComboBoxExT(HWND hWnd = NULL) : CComboBoxT< TBase >(hWnd)
+ { }
+
+ CComboBoxExT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_COMBOBOXEX;
+ }
+
+ CImageList GetImageList() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_GETIMAGELIST, 0, 0L));
+ }
+
+ CImageList SetImageList(HIMAGELIST hImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_SETIMAGELIST, 0, (LPARAM)hImageList));
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ DWORD GetExtendedStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, 0, 0L);
+ }
+
+ DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, dwExMask, dwExStyle);
+ }
+
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CBEM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CBEM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_WINNT >= 0x0501)
+ void SetWindowTheme(LPCWSTR lpstrTheme)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, CBEM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+// Operations
+ int InsertItem(const COMBOBOXEXITEM* lpcCBItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)lpcCBItem);
+ }
+
+ int InsertItem(UINT nMask, int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage,
+ int iIndent, int iOverlay, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = nMask;
+ cbex.iItem = nIndex;
+ cbex.pszText = (LPTSTR) lpszItem;
+ cbex.iImage = nImage;
+ cbex.iSelectedImage = nSelImage;
+ cbex.iIndent = iIndent;
+ cbex.iOverlay = iOverlay;
+ cbex.lParam = lParam;
+ return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex);
+ }
+
+ int InsertItem(int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT | CBEIF_LPARAM;
+ cbex.iItem = nIndex;
+ cbex.pszText = (LPTSTR) lpszItem;
+ cbex.iImage = nImage;
+ cbex.iSelectedImage = nSelImage;
+ cbex.iIndent = iIndent;
+ cbex.lParam = lParam;
+ return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex);
+ }
+
+ int AddItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam)
+ {
+ return InsertItem(nMask, -1, lpszItem, nImage, nSelImage, iIndent, iOverlay, lParam);
+ }
+
+ int AddItem(LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0)
+ {
+ return InsertItem(-1, lpszItem, nImage, nSelImage, iIndent, lParam);
+ }
+
+ int DeleteItem(int nIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, CBEM_DELETEITEM, nIndex, 0L);
+ }
+
+ BOOL GetItem(PCOMBOBOXEXITEM pCBItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)pCBItem);
+ }
+
+ BOOL SetItem(const COMBOBOXEXITEM* lpcCBItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)lpcCBItem);
+ }
+
+ int SetItem(int nIndex, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage,
+ int iIndent, int iOverlay, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = nMask;
+ cbex.iItem = nIndex;
+ cbex.pszText = (LPTSTR) lpszItem;
+ cbex.iImage = nImage;
+ cbex.iSelectedImage = nSelImage;
+ cbex.iIndent = iIndent;
+ cbex.iOverlay = iOverlay;
+ cbex.lParam = lParam;
+ return (int)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)&cbex);
+ }
+
+ BOOL GetItemText(int nIndex, LPTSTR lpszItem, int nLen) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpszItem != NULL);
+
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = CBEIF_TEXT;
+ cbex.iItem = nIndex;
+ cbex.pszText = lpszItem;
+ cbex.cchTextMax = nLen;
+
+ return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetItemText(int nIndex, BSTR& bstrText) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(bstrText == NULL);
+
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = CBEIF_TEXT;
+ cbex.iItem = nIndex;
+
+ LPTSTR lpstrText = NULL;
+ BOOL bRet = FALSE;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrText = new TCHAR[nLen]);
+ if(lpstrText == NULL)
+ break;
+ lpstrText[0] = NULL;
+ cbex.pszText = lpstrText;
+ cbex.cchTextMax = nLen;
+ bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);
+ if(!bRet || (lstrlen(cbex.pszText) < nLen - 1))
+ break;
+ delete [] lpstrText;
+ lpstrText = NULL;
+ }
+
+ if(lpstrText != NULL)
+ {
+ if(bRet)
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ delete [] lpstrText;
+ }
+
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL GetItemText(int nIndex, _CSTRING_NS::CString& strText) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ COMBOBOXEXITEM cbex = { 0 };
+ cbex.mask = CBEIF_TEXT;
+ cbex.iItem = nIndex;
+
+ strText.Empty();
+ BOOL bRet = FALSE;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ cbex.pszText = strText.GetBufferSetLength(nLen);
+ if(cbex.pszText == NULL)
+ {
+ bRet = FALSE;
+ break;
+ }
+ cbex.cchTextMax = nLen;
+ bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);
+ if(!bRet || (lstrlen(cbex.pszText) < nLen - 1))
+ break;
+ }
+ strText.ReleaseBuffer();
+ return bRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL SetItemText(int nIndex, LPCTSTR lpszItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return SetItem(nIndex, CBEIF_TEXT, lpszItem, 0, 0, 0, 0, 0);
+ }
+
+ CComboBox GetComboCtrl() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CComboBox((HWND)::SendMessage(m_hWnd, CBEM_GETCOMBOCONTROL, 0, 0L));
+ }
+
+ CEdit GetEditCtrl() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CEdit((HWND)::SendMessage(m_hWnd, CBEM_GETEDITCONTROL, 0, 0L));
+ }
+
+ BOOL HasEditChanged() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, CBEM_HASEDITCHANGED, 0, 0L);
+ }
+
+// Non-functional
+ int AddString(LPCTSTR /*lpszItem*/)
+ {
+ ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem
+ return 0;
+ }
+
+ int InsertString(int /*nIndex*/, LPCTSTR /*lpszString*/)
+ {
+ ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem
+ return 0;
+ }
+
+ int Dir(UINT /*attr*/, LPCTSTR /*lpszWildCard*/)
+ {
+ ATLASSERT(FALSE); // Not available in CComboBoxEx
+ return 0;
+ }
+
+ int FindString(int /*nStartAfter*/, LPCTSTR /*lpszString*/) const
+ {
+ ATLASSERT(FALSE); // Not available in CComboBoxEx; try FindStringExact
+ return 0;
+ }
+};
+
+typedef CComboBoxExT<ATL::CWindow> CComboBoxEx;
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMonthCalendarCtrl
+
+template <class TBase>
+class CMonthCalendarCtrlT : public TBase
+{
+public:
+// Constructors
+ CMonthCalendarCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CMonthCalendarCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return MONTHCAL_CLASS;
+ }
+
+ COLORREF GetColor(int nColorType) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, MCM_GETCOLOR, nColorType, 0L);
+ }
+
+ COLORREF SetColor(int nColorType, COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, MCM_SETCOLOR, nColorType, clr);
+ }
+
+ BOOL GetCurSel(LPSYSTEMTIME lpSysTime) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETCURSEL, 0, (LPARAM)lpSysTime);
+ }
+
+ BOOL SetCurSel(LPSYSTEMTIME lpSysTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETCURSEL, 0, (LPARAM)lpSysTime);
+ }
+
+ int GetFirstDayOfWeek(BOOL* pbLocaleVal = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_GETFIRSTDAYOFWEEK, 0, 0L);
+ if(pbLocaleVal != NULL)
+ *pbLocaleVal = (BOOL)HIWORD(dwRet);
+ return (int)(short)LOWORD(dwRet);
+ }
+
+ int SetFirstDayOfWeek(int nDay, BOOL* pbLocaleVal = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_SETFIRSTDAYOFWEEK, 0, nDay);
+ if(pbLocaleVal != NULL)
+ *pbLocaleVal = (BOOL)HIWORD(dwRet);
+ return (int)(short)LOWORD(dwRet);
+ }
+
+ int GetMaxSelCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_GETMAXSELCOUNT, 0, 0L);
+ }
+
+ BOOL SetMaxSelCount(int nMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETMAXSELCOUNT, nMax, 0L);
+ }
+
+ int GetMonthDelta() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_GETMONTHDELTA, 0, 0L);
+ }
+
+ int SetMonthDelta(int nDelta)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_SETMONTHDELTA, nDelta, 0L);
+ }
+
+ DWORD GetRange(LPSYSTEMTIME lprgSysTimeArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, MCM_GETRANGE, 0, (LPARAM)lprgSysTimeArray);
+ }
+
+ BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETRANGE, dwFlags, (LPARAM)lprgSysTimeArray);
+ }
+
+ BOOL GetSelRange(LPSYSTEMTIME lprgSysTimeArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETSELRANGE, 0, (LPARAM)lprgSysTimeArray);
+ }
+
+ BOOL SetSelRange(LPSYSTEMTIME lprgSysTimeArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETSELRANGE, 0, (LPARAM)lprgSysTimeArray);
+ }
+
+ BOOL GetToday(LPSYSTEMTIME lpSysTime) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETTODAY, 0, (LPARAM)lpSysTime);
+ }
+
+ void SetToday(LPSYSTEMTIME lpSysTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, MCM_SETTODAY, 0, (LPARAM)lpSysTime);
+ }
+
+ BOOL GetMinReqRect(LPRECT lpRectInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETMINREQRECT, 0, (LPARAM)lpRectInfo);
+ }
+
+ int GetMaxTodayWidth() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_GETMAXTODAYWIDTH, 0, 0L);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetUnicodeFormat() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETUNICODEFORMAT, 0, 0L);
+ }
+
+ BOOL SetUnicodeFormat(BOOL bUnicode = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETUNICODEFORMAT, bUnicode, 0L);
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ DWORD GetCurrentView() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, MCM_GETCURRENTVIEW, 0, 0L);
+ }
+
+ BOOL SetCurrentView(DWORD dwView)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETCURRENTVIEW, 0, dwView);
+ }
+
+ DWORD GetCalendarCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, MCM_GETCALENDARCOUNT, 0, 0L);
+ }
+
+ BOOL GetCalendarGridInfo(PMCGRIDINFO pGridInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_GETCALENDARGRIDINFO, 0, (LPARAM)pGridInfo);
+ }
+
+ CALID GetCALID() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (CALID)::SendMessage(m_hWnd, MCM_GETCALID, 0, 0L);
+ }
+
+ void SetCALID(CALID calid)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, MCM_SETCALID, (LPARAM)calid, 0L);
+ }
+
+ int GetCalendarBorder() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_GETCALENDARBORDER, 0, 0L);
+ }
+
+ void SetCalendarBorder(int cxyBorder, BOOL bSet = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, MCM_SETCALENDARBORDER, (WPARAM)bSet, (LPARAM)cxyBorder);
+ }
+#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+
+// Operations
+ int GetMonthRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, MCM_GETMONTHRANGE, dwFlags, (LPARAM)lprgSysTimeArray);
+ }
+
+ BOOL SetDayState(int nMonths, LPMONTHDAYSTATE lpDayStateArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, MCM_SETDAYSTATE, nMonths, (LPARAM)lpDayStateArray);
+ }
+
+ DWORD HitTest(PMCHITTESTINFO pMCHitTest) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, MCM_HITTEST, 0, (LPARAM)pMCHitTest);
+ }
+
+#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ void SizeRectToMin(LPRECT lpRect)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, MCM_SIZERECTTOMIN, 0, (LPARAM)lpRect);
+ }
+#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+};
+
+typedef CMonthCalendarCtrlT<ATL::CWindow> CMonthCalendarCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDateTimePickerCtrl
+
+template <class TBase>
+class CDateTimePickerCtrlT : public TBase
+{
+public:
+// Constructors
+ CDateTimePickerCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CDateTimePickerCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Operations
+ static LPCTSTR GetWndClassName()
+ {
+ return DATETIMEPICK_CLASS;
+ }
+
+ BOOL SetFormat(LPCTSTR lpszFormat)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DTM_SETFORMAT, 0, (LPARAM)lpszFormat);
+ }
+
+ COLORREF GetMonthCalColor(int nColorType) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, DTM_GETMCCOLOR, nColorType, 0L);
+ }
+
+ COLORREF SetMonthCalColor(int nColorType, COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, DTM_SETMCCOLOR, nColorType, clr);
+ }
+
+ DWORD GetRange(LPSYSTEMTIME lpSysTimeArray) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, DTM_GETRANGE, 0, (LPARAM)lpSysTimeArray);
+ }
+
+ BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lpSysTimeArray)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DTM_SETRANGE, dwFlags, (LPARAM)lpSysTimeArray);
+ }
+
+ DWORD GetSystemTime(LPSYSTEMTIME lpSysTime) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)lpSysTime);
+ }
+
+ BOOL SetSystemTime(DWORD dwFlags, LPSYSTEMTIME lpSysTime)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DTM_SETSYSTEMTIME, dwFlags, (LPARAM)lpSysTime);
+ }
+
+ CMonthCalendarCtrl GetMonthCal() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CMonthCalendarCtrl((HWND)::SendMessage(m_hWnd, DTM_GETMONTHCAL, 0, 0L));
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ CFontHandle GetMonthCalFont() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CFontHandle((HFONT)::SendMessage(m_hWnd, DTM_GETMCFONT, 0, 0L));
+ }
+
+ void SetMonthCalFont(HFONT hFont, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_SETMCFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0));
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ DWORD GetMonthCalStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, DTM_GETMCSTYLE, 0, 0L);
+ }
+
+ DWORD SetMonthCalStyle(DWORD dwStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (DWORD)::SendMessage(m_hWnd, DTM_SETMCSTYLE, 0, (LPARAM)dwStyle);
+ }
+
+ void GetDateTimePickerInfo(LPDATETIMEPICKERINFO lpPickerInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_GETDATETIMEPICKERINFO, 0, (LPARAM)lpPickerInfo);
+ }
+
+ BOOL GetIdealSize(LPSIZE lpSize) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)lpSize);
+ }
+
+ void CloseMonthCal()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_CLOSEMONTHCAL, 0, 0L);
+ }
+#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+};
+
+typedef CDateTimePickerCtrlT<ATL::CWindow> CDateTimePickerCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFlatScrollBarImpl - support for flat scroll bars
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+template <class T>
+class CFlatScrollBarImpl
+{
+public:
+// Initialization
+ BOOL FlatSB_Initialize()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::InitializeFlatSB(pT->m_hWnd);
+ }
+
+ HRESULT FlatSB_Uninitialize()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::UninitializeFlatSB(pT->m_hWnd);
+ }
+
+// Flat scroll bar properties
+ BOOL FlatSB_GetScrollProp(UINT uIndex, LPINT lpnValue) const
+ {
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_GetScrollProp(pT->m_hWnd, uIndex, lpnValue);
+ }
+
+ BOOL FlatSB_SetScrollProp(UINT uIndex, int nValue, BOOL bRedraw = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_SetScrollProp(pT->m_hWnd, uIndex, nValue, bRedraw);
+ }
+
+// Attributes
+ int FlatSB_GetScrollPos(int nBar) const
+ {
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_GetScrollPos(pT->m_hWnd, nBar);
+ }
+
+ int FlatSB_SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_SetScrollPos(pT->m_hWnd, nBar, nPos, bRedraw);
+ }
+
+ BOOL FlatSB_GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const
+ {
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_GetScrollRange(pT->m_hWnd, nBar, lpMinPos, lpMaxPos);
+ }
+
+ BOOL FlatSB_SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_SetScrollRange(pT->m_hWnd, nBar, nMinPos, nMaxPos, bRedraw);
+ }
+
+ BOOL FlatSB_GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) const
+ {
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_GetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo);
+ }
+
+ int FlatSB_SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_SetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo, bRedraw);
+ }
+
+// Operations
+ BOOL FlatSB_ShowScrollBar(UINT nBar, BOOL bShow = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_ShowScrollBar(pT->m_hWnd, nBar, bShow);
+ }
+
+ BOOL FlatSB_EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::FlatSB_EnableScrollBar(pT->m_hWnd, uSBFlags, uArrowFlags);
+ }
+};
+
+template <class TBase>
+class CFlatScrollBarT : public TBase, public CFlatScrollBarImpl<CFlatScrollBarT< TBase > >
+{
+public:
+ CFlatScrollBarT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CFlatScrollBarT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+};
+
+typedef CFlatScrollBarT<ATL::CWindow> CFlatScrollBar;
+
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CIPAddressCtrl
+
+#if (_WIN32_IE >= 0x0400)
+
+template <class TBase>
+class CIPAddressCtrlT : public TBase
+{
+public:
+// Constructors
+ CIPAddressCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CIPAddressCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Atteributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_IPADDRESS;
+ }
+
+ BOOL IsBlank() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, IPM_ISBLANK, 0, 0L);
+ }
+
+ int GetAddress(LPDWORD lpdwAddress) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM)lpdwAddress);
+ }
+
+ void SetAddress(DWORD dwAddress)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IPM_SETADDRESS, 0, dwAddress);
+ }
+
+ void ClearAddress()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IPM_CLEARADDRESS, 0, 0L);
+ }
+
+ void SetRange(int nField, WORD wRange)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IPM_SETRANGE, nField, wRange);
+ }
+
+ void SetRange(int nField, BYTE nMin, BYTE nMax)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IPM_SETRANGE, nField, MAKEIPRANGE(nMin, nMax));
+ }
+
+ void SetFocus(int nField)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IPM_SETFOCUS, nField, 0L);
+ }
+};
+
+typedef CIPAddressCtrlT<ATL::CWindow> CIPAddressCtrl;
+
+#endif // (_WIN32_IE >= 0x0400)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPagerCtrl
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+template <class TBase>
+class CPagerCtrlT : public TBase
+{
+public:
+// Constructors
+ CPagerCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CPagerCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_PAGESCROLLER;
+ }
+
+ int GetButtonSize() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_GETBUTTONSIZE, 0, 0L);
+ }
+
+ int SetButtonSize(int nButtonSize)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_SETBUTTONSIZE, 0, nButtonSize);
+ }
+
+ DWORD GetButtonState(int nButton) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nButton == PGB_TOPORLEFT || nButton == PGB_BOTTOMORRIGHT);
+ return (DWORD)::SendMessage(m_hWnd, PGM_GETBUTTONSTATE, 0, nButton);
+ }
+
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PGM_GETBKCOLOR, 0, 0L);
+ }
+
+ COLORREF SetBkColor(COLORREF clrBk)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (COLORREF)::SendMessage(m_hWnd, PGM_SETBKCOLOR, 0, (LPARAM)clrBk);
+ }
+
+ int GetBorder() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_GETBORDER, 0, 0L);
+ }
+
+ int SetBorder(int nBorderSize)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_SETBORDER, 0, nBorderSize);
+ }
+
+ int GetPos() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_GETPOS, 0, 0L);
+ }
+
+ int SetPos(int nPos)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PGM_SETPOS, 0, nPos);
+ }
+
+// Operations
+ void SetChild(HWND hWndChild)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PGM_SETCHILD, 0, (LPARAM)hWndChild);
+ }
+
+ void ForwardMouse(BOOL bForward = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PGM_FORWARDMOUSE, bForward, 0L);
+ }
+
+ void RecalcSize()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PGM_RECALCSIZE, 0, 0L);
+ }
+
+ void GetDropTarget(IDropTarget** ppDropTarget)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(ppDropTarget != NULL);
+ ::SendMessage(m_hWnd, PGM_GETDROPTARGET, 0, (LPARAM)ppDropTarget);
+ }
+};
+
+typedef CPagerCtrlT<ATL::CWindow> CPagerCtrl;
+
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CLinkCtrl - Windows SYSLINK control
+
+#if (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)
+
+template <class TBase>
+class CLinkCtrlT : public TBase
+{
+public:
+// Constructors
+ CLinkCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CLinkCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+#ifdef _UNICODE
+ return WC_LINK;
+#else // !_UNICODE
+ return "SysLink";
+#endif // !_UNICODE
+ }
+
+ int GetIdealHeight(int cxMaxWidth = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LM_GETIDEALHEIGHT, cxMaxWidth, 0L);
+ }
+
+ BOOL GetItem(PLITEM pLItem) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LM_GETITEM, 0, (LPARAM)pLItem);
+ }
+
+ BOOL SetItem(PLITEM pLItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LM_SETITEM, 0, (LPARAM)pLItem);
+ }
+
+ // Vista only
+ int GetIdealSize(SIZE& size, int cxMaxWidth = 0) const
+ {
+#ifndef LM_GETIDEALSIZE
+ const UINT LM_GETIDEALSIZE = LM_GETIDEALHEIGHT;
+#endif
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, LM_GETIDEALSIZE, cxMaxWidth, (LPARAM)&size);
+ }
+
+// Operations
+ BOOL HitTest(PLHITTESTINFO pLHitTestInfo) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, LM_HITTEST, 0, (LPARAM)pLHitTestInfo);
+ }
+};
+
+typedef CLinkCtrlT<ATL::CWindow> CLinkCtrl;
+
+#endif // (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCustomDraw - MI class for custom-draw support
+
+template <class T>
+class CCustomDraw
+{
+public:
+#if (_ATL_VER < 0x0700)
+ BOOL m_bHandledCD;
+
+ BOOL IsMsgHandled() const
+ {
+ return m_bHandledCD;
+ }
+
+ void SetMsgHandled(BOOL bHandled)
+ {
+ m_bHandledCD = bHandled;
+ }
+#endif // !(_ATL_VER < 0x0700)
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CCustomDraw< T >)
+ NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
+ ALT_MSG_MAP(1)
+ REFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
+ END_MSG_MAP()
+
+// message handler
+ LRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetMsgHandled(TRUE);
+ LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh;
+ DWORD dwRet = 0;
+ switch(lpNMCustomDraw->dwDrawStage)
+ {
+ case CDDS_PREPAINT:
+ dwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_POSTPAINT:
+ dwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_PREERASE:
+ dwRet = pT->OnPreErase(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_POSTERASE:
+ dwRet = pT->OnPostErase(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_ITEMPREPAINT:
+ dwRet = pT->OnItemPrePaint(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_ITEMPOSTPAINT:
+ dwRet = pT->OnItemPostPaint(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_ITEMPREERASE:
+ dwRet = pT->OnItemPreErase(idCtrl, lpNMCustomDraw);
+ break;
+ case CDDS_ITEMPOSTERASE:
+ dwRet = pT->OnItemPostErase(idCtrl, lpNMCustomDraw);
+ break;
+#if (_WIN32_IE >= 0x0400)
+ case (CDDS_ITEMPREPAINT | CDDS_SUBITEM):
+ dwRet = pT->OnSubItemPrePaint(idCtrl, lpNMCustomDraw);
+ break;
+#endif // (_WIN32_IE >= 0x0400)
+ default:
+ pT->SetMsgHandled(FALSE);
+ break;
+ }
+ bHandled = pT->IsMsgHandled();
+ return dwRet;
+ }
+
+// Overrideables
+ DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+ DWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ DWORD OnSubItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_DODEFAULT;
+ }
+#endif // (_WIN32_IE >= 0x0400)
+};
+
+
+// --- Windows CE common controls ---
+
+#ifdef _WIN32_WCE
+
+///////////////////////////////////////////////////////////////////////////////
+// CCECommandBarCtrl
+
+template <class TBase>
+class CCECommandBarCtrlT : public TBase
+{
+public:
+// Constructors
+ CCECommandBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { }
+
+ CCECommandBarCtrlT< TBase >& operator=(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ BOOL IsVisible() const
+ {
+ return IsWindowVisible();
+ }
+
+ int GetHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_Height(m_hWnd);
+ }
+
+ HMENU GetMenu(WORD wButton) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_GetMenu(m_hWnd, wButton);
+ }
+
+// Operations
+ HWND Create(HWND hWndParent, int nCmdBarID)
+ {
+ m_hWnd = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), hWndParent, nCmdBarID);
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_hWnd;
+ }
+
+ void Destroy()
+ {
+ DestroyWindow();
+ }
+
+ BOOL Show(BOOL bShow = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_Show(m_hWnd, bShow);
+ }
+
+ BOOL DrawMenuBar(WORD wButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_DrawMenuBar(m_hWnd, wButton);
+ }
+
+ BOOL AddAdornments(DWORD dwFlags = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_AddAdornments(m_hWnd, dwFlags, 0);
+ }
+
+ int AddBitmap(int nBitmapID, int nNumImages)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_AddBitmap(m_hWnd, ModuleHelper::GetResourceInstance(), nBitmapID, nNumImages, 16, 16);
+ }
+
+ BOOL AddButtons(UINT uNumButtons, LPTBBUTTON lpButtons)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CommandBar_AddButtons(m_hWnd, uNumButtons, lpButtons);
+ }
+
+ BOOL AddToolTips(UINT uNumToolTips, LPTSTR lpToolTips)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CommandBar_AddToolTips(m_hWnd, uNumToolTips, lpToolTips);
+ }
+
+ BOOL InsertButton(int nButton, LPTBBUTTON lpButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CommandBar_InsertButton(m_hWnd, nButton, lpButton);
+ }
+
+ HWND InsertComboBox(int nWidth, UINT dwStyle, WORD wComboBoxID, WORD wButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_InsertComboBox(m_hWnd, ModuleHelper::GetModuleInstance(), nWidth, dwStyle, wComboBoxID, wButton);
+ }
+
+ BOOL InsertMenubar(WORD wMenuID, WORD wButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_InsertMenubar(m_hWnd, ModuleHelper::GetResourceInstance(), wMenuID, wButton);
+ }
+
+ BOOL InsertMenubarEx(ATL::_U_STRINGorID menu, WORD wButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBar_InsertMenubarEx(m_hWnd, ModuleHelper::GetResourceInstance(), (LPTSTR)menu.m_lpstr, wButton);
+ }
+
+ BOOL IsCommandBarMessage(LPMSG lpMsg)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::IsCommandBarMessage(m_hWnd, lpMsg);
+ }
+};
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC MenuBar
+ typedef CCECommandBarCtrlT<CToolBarCtrl> CMenuBarCtrl;
+#else
+ typedef CCECommandBarCtrlT<CToolBarCtrl> CCECommandBarCtrl;
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+
+///////////////////////////////////////////////////////////////////////////////
+// CCECommandBandsCtrl
+
+template <class TBase>
+class CCECommandBandsCtrlT : public TBase
+{
+public:
+// Constructors
+ CCECommandBandsCtrlT(HWND hWnd = NULL) : TBase(hWnd) { }
+
+ CCECommandBandsCtrlT< TBase >& operator=(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ BOOL IsVisible() const
+ {
+ return IsWindowVisible();
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ UINT GetHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CommandBands_Height(m_hWnd);
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+ HWND GetCommandBar(UINT uBand) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBands_GetCommandBar(m_hWnd, uBand);
+ }
+
+ BOOL GetRestoreInformation(UINT uBand, LPCOMMANDBANDSRESTOREINFO pcbr) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBands_GetRestoreInformation(m_hWnd, uBand, pcbr);
+ }
+
+// Operations
+ HWND Create(HWND hWndParent, UINT wID, DWORD dwStyles, HIMAGELIST hImageList = NULL)
+ {
+ m_hWnd = ::CommandBands_Create(ModuleHelper::GetModuleInstance(), hWndParent, wID, dwStyles, hImageList);
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_hWnd;
+ }
+
+ BOOL AddAdornments(DWORD dwFlags = 0, LPREBARBANDINFO prbbi = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBands_AddAdornments(m_hWnd, ModuleHelper::GetModuleInstance(), dwFlags, prbbi);
+ }
+
+ BOOL AddBands(UINT uBandCount, LPREBARBANDINFO prbbi)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBands_AddBands(m_hWnd, ModuleHelper::GetModuleInstance(), uBandCount, prbbi);
+ }
+
+ BOOL Show(BOOL bShow = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::CommandBands_Show(m_hWnd, bShow);
+ }
+};
+
+typedef CCECommandBandsCtrlT<ATL::CWindow> CCECommandBandsCtrl;
+
+#endif // _WIN32_WCE
+
+}; // namespace WTL
+
+#endif // __ATLCTRLS_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLCTRLW_H__
+#define __ATLCTRLW_H__
+
+#pragma once
+
+#ifdef _WIN32_WCE
+ #error atlctrlw.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLAPP_H__
+ #error atlctrlw.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLCTRLS_H__
+ #error atlctrlw.h requires atlctrls.h to be included first
+#endif
+
+#if (_WIN32_IE < 0x0400)
+ #error atlctrlw.h requires _WIN32_IE >= 0x0400
+#endif
+
+// Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support
+#if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
+ #define _WTL_CMDBAR_VISTA_MENUS 1
+#endif
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501))
+ #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
+ #endif
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CCommandBarCtrlImpl<T, TBase, TWinTraits>
+// CCommandBarCtrl
+// CMDICommandBarCtrlImpl<T, TBase, TWinTraits>
+// CMDICommandBarCtrl
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// Command Bars
+
+// Window Styles:
+#define CBRWS_TOP CCS_TOP
+#define CBRWS_BOTTOM CCS_BOTTOM
+#define CBRWS_NORESIZE CCS_NORESIZE
+#define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN
+#define CBRWS_NODIVIDER CCS_NODIVIDER
+
+// Extended styles
+#define CBR_EX_TRANSPARENT 0x00000001L
+#define CBR_EX_SHAREMENU 0x00000002L
+#define CBR_EX_ALTFOCUSMODE 0x00000004L
+#define CBR_EX_TRACKALWAYS 0x00000008L
+#define CBR_EX_NOVISTAMENUS 0x00000010L
+
+// standard command bar styles
+#define ATL_SIMPLE_CMDBAR_PANE_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)
+
+// Messages - support chevrons for frame windows
+#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
+#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
+#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
+
+typedef struct tagCBRPOPUPMENU
+{
+ int cbSize;
+ HMENU hMenu; // popup menu do display
+ UINT uFlags; // TPM_* flags for ::TrackPopupMenuEx
+ int x;
+ int y;
+ LPTPMPARAMS lptpm; // ptr to TPMPARAMS for ::TrackPopupMenuEx
+} CBRPOPUPMENU, *LPCBRPOPUPMENU;
+
+// helper class
+template <class T>
+class CSimpleStack : public ATL::CSimpleArray< T >
+{
+public:
+ BOOL Push(T t)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize());
+#endif
+ return Add(t);
+ }
+
+ T Pop()
+ {
+ int nLast = GetSize() - 1;
+ if(nLast < 0)
+ return NULL; // must be able to convert to NULL
+ T t = m_aT[nLast];
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize());
+#endif
+ if(!RemoveAt(nLast))
+ return NULL;
+ return t;
+ }
+
+ T GetCurrent()
+ {
+ int nLast = GetSize() - 1;
+ if(nLast < 0)
+ return NULL; // must be able to convert to NULL
+ return m_aT[nLast];
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCommandBarCtrlBase - base class for the Command Bar implementation
+
+class CCommandBarCtrlBase : public CToolBarCtrl
+{
+public:
+ struct _MsgHookData
+ {
+ HHOOK hMsgHook;
+ DWORD dwUsage;
+
+ _MsgHookData() : hMsgHook(NULL), dwUsage(0)
+ { }
+ };
+
+ typedef ATL::CSimpleMap<DWORD, _MsgHookData*> CMsgHookMap;
+ static CMsgHookMap* s_pmapMsgHook;
+
+ static HHOOK s_hCreateHook;
+ static bool s_bW2K; // For animation flag
+ static CCommandBarCtrlBase* s_pCurrentBar;
+ static bool s_bStaticInit;
+
+ CSimpleStack<HWND> m_stackMenuWnd;
+ CSimpleStack<HMENU> m_stackMenuHandle;
+
+ HWND m_hWndHook;
+ DWORD m_dwMagic;
+
+
+ CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314)
+ {
+ // init static variables
+ if(!s_bStaticInit)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n"));
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ if(!s_bStaticInit)
+ {
+ // Just in case...
+ AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);
+ // Animation on Win2000 only
+ s_bW2K = !AtlIsOldWindows();
+ // done
+ s_bStaticInit = true;
+ }
+
+ lock.Unlock();
+ }
+ }
+
+ bool IsCommandBarBase() const { return m_dwMagic == 1314; }
+};
+
+__declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL;
+__declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL;
+__declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL;
+__declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false;
+__declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCommandBarCtrl - ATL implementation of Command Bars
+
+template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
+{
+public:
+ DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
+
+// Declarations
+ struct _MenuItemData // menu item data
+ {
+ DWORD dwMagic;
+ LPTSTR lpstrText;
+ UINT fType;
+ UINT fState;
+ int iButton;
+
+ _MenuItemData() { dwMagic = 0x1313; }
+ bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); }
+ };
+
+ struct _ToolBarData // toolbar resource data
+ {
+ WORD wVersion;
+ WORD wWidth;
+ WORD wHeight;
+ WORD wItemCount;
+ //WORD aItems[wItemCount]
+
+ WORD* items()
+ { return (WORD*)(this+1); }
+ };
+
+// Constants
+ enum _CmdBarDrawConstants
+ {
+ s_kcxGap = 1,
+ s_kcxTextMargin = 2,
+ s_kcxButtonMargin = 3,
+ s_kcyButtonMargin = 3
+ };
+
+ enum
+ {
+ _nMaxMenuItemTextLength = 100,
+ _chChevronShortcut = _T('/')
+ };
+
+#ifndef DT_HIDEPREFIX
+ enum { DT_HIDEPREFIX = 0x00100000 };
+#endif // !DT_HIDEPREFIX
+
+// Data members
+ HMENU m_hMenu;
+ HIMAGELIST m_hImageList;
+ ATL::CSimpleValArray<WORD> m_arrCommand;
+
+ DWORD m_dwExtendedStyle; // Command Bar specific extended styles
+
+ ATL::CContainedWindow m_wndParent;
+
+ bool m_bMenuActive:1;
+ bool m_bAttachedMenu:1;
+ bool m_bImagesVisible:1;
+ bool m_bPopupItem:1;
+ bool m_bContextMenu:1;
+ bool m_bEscapePressed:1;
+ bool m_bSkipMsg:1;
+ bool m_bParentActive:1;
+ bool m_bFlatMenus:1;
+ bool m_bUseKeyboardCues:1;
+ bool m_bShowKeyboardCues:1;
+ bool m_bAllowKeyboardCues:1;
+ bool m_bKeyboardInput:1;
+ bool m_bAlphaImages:1;
+ bool m_bLayoutRTL:1;
+ bool m_bSkipPostDown:1;
+ bool m_bVistaMenus:1;
+
+ int m_nPopBtn;
+ int m_nNextPopBtn;
+
+ SIZE m_szBitmap;
+ SIZE m_szButton;
+
+ COLORREF m_clrMask;
+ CFont m_fontMenu; // used internally, only to measure text
+
+ UINT m_uSysKey;
+
+ HWND m_hWndFocus; // Alternate focus mode
+
+ int m_cxExtraSpacing;
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ ATL::CSimpleValArray<HBITMAP> m_arrVistaBitmap; // Bitmaps for Vista menus
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+// Constructor/destructor
+ CCommandBarCtrlImpl() :
+ m_hMenu(NULL),
+ m_hImageList(NULL),
+ m_wndParent(this, 1),
+ m_bMenuActive(false),
+ m_bAttachedMenu(false),
+ m_nPopBtn(-1),
+ m_nNextPopBtn(-1),
+ m_bPopupItem(false),
+ m_bImagesVisible(true),
+ m_bSkipMsg(false),
+ m_uSysKey(0),
+ m_hWndFocus(NULL),
+ m_bContextMenu(false),
+ m_bEscapePressed(false),
+ m_clrMask(RGB(192, 192, 192)),
+ m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS),
+ m_bParentActive(true),
+ m_bFlatMenus(false),
+ m_bUseKeyboardCues(false),
+ m_bShowKeyboardCues(false),
+ m_bAllowKeyboardCues(true),
+ m_bKeyboardInput(false),
+ m_cxExtraSpacing(0),
+ m_bAlphaImages(false),
+ m_bLayoutRTL(false),
+ m_bSkipPostDown(false),
+ m_bVistaMenus(false)
+ {
+ SetImageSize(16, 15); // default
+ }
+
+ ~CCommandBarCtrlImpl()
+ {
+ if(m_wndParent.IsWindow())
+/*scary!*/ m_wndParent.UnsubclassWindow();
+
+ if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)
+ ::DestroyMenu(m_hMenu);
+
+ if(m_hImageList != NULL)
+ ::ImageList_Destroy(m_hImageList);
+ }
+
+// Attributes
+ DWORD GetCommandBarExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ return dwPrevStyle;
+ }
+
+ CMenuHandle GetMenu() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_hMenu;
+ }
+
+ COLORREF GetImageMaskColor() const
+ {
+ return m_clrMask;
+ }
+
+ COLORREF SetImageMaskColor(COLORREF clrMask)
+ {
+ COLORREF clrOld = m_clrMask;
+ m_clrMask = clrMask;
+ return clrOld;
+ }
+
+ bool GetImagesVisible() const
+ {
+ return m_bImagesVisible;
+ }
+
+ bool SetImagesVisible(bool bVisible)
+ {
+ bool bOld = m_bImagesVisible;
+ m_bImagesVisible = bVisible;
+ return bOld;
+ }
+
+ void GetImageSize(SIZE& size) const
+ {
+ size = m_szBitmap;
+ }
+
+ bool SetImageSize(SIZE& size)
+ {
+ return SetImageSize(size.cx, size.cy);
+ }
+
+ bool SetImageSize(int cx, int cy)
+ {
+ if(m_hImageList != NULL)
+ {
+ if(::ImageList_GetImageCount(m_hImageList) == 0) // empty
+ {
+ ::ImageList_Destroy(m_hImageList);
+ m_hImageList = NULL;
+ }
+ else
+ {
+ return false; // can't set, image list exists
+ }
+ }
+
+ if(cx == 0 || cy == 0)
+ return false;
+
+ m_szBitmap.cx = cx;
+ m_szBitmap.cy = cy;
+ m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin;
+ m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin;
+
+ return true;
+ }
+
+ bool GetAlphaImages() const
+ {
+ return m_bAlphaImages;
+ }
+
+ bool SetAlphaImages(bool bAlphaImages)
+ {
+ if(m_hImageList != NULL)
+ {
+ if(::ImageList_GetImageCount(m_hImageList) == 0) // empty
+ {
+ ::ImageList_Destroy(m_hImageList);
+ m_hImageList = NULL;
+ }
+ else
+ {
+ return false; // can't set, image list exists
+ }
+ }
+
+ m_bAlphaImages = bAlphaImages;
+ return true;
+ }
+
+ HWND GetCmdBar() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
+ }
+
+// Methods
+ HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ UINT nID = 0, LPVOID lpCreateParam = NULL)
+ {
+ // These styles are required for command bars
+ dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT;
+#if (_MSC_VER >= 1300)
+ return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
+ return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
+#endif // !(_MSC_VER >= 1300)
+ }
+
+ BOOL AttachToWindow(HWND hWnd)
+ {
+ ATLASSERT(m_hWnd == NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ BOOL bRet = SubclassWindow(hWnd);
+ if(bRet)
+ {
+ m_bAttachedMenu = true;
+ T* pT = static_cast<T*>(this);
+ pT->GetSystemSettings();
+ }
+ return bRet;
+ }
+
+ BOOL LoadMenu(ATL::_U_STRINGorID menu)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ if(m_bAttachedMenu) // doesn't work in this mode
+ return FALSE;
+ if(menu.m_lpstr == NULL)
+ return FALSE;
+
+ HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);
+ if(hMenu == NULL)
+ return FALSE;
+
+ return AttachMenu(hMenu);
+ }
+
+ BOOL AttachMenu(HMENU hMenu)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));
+ if(hMenu != NULL && !::IsMenu(hMenu))
+ return FALSE;
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ // remove Vista bitmaps if used
+ if(m_bVistaMenus && (m_hMenu != NULL))
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_RemoveVistaBitmapsFromMenu();
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+ // destroy old menu, if needed, and set new one
+ if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)
+ ::DestroyMenu(m_hMenu);
+
+ m_hMenu = hMenu;
+
+ if(m_bAttachedMenu) // Nothing else in this mode
+ return TRUE;
+
+ // Build buttons according to menu
+ SetRedraw(FALSE);
+
+ // Clear all buttons
+ int nCount = GetButtonCount();
+ for(int i = 0; i < nCount; i++)
+ ATLVERIFY(DeleteButton(0) != FALSE);
+
+ // Add buttons for each menu item
+ if(m_hMenu != NULL)
+ {
+ int nItems = ::GetMenuItemCount(m_hMenu);
+
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ TCHAR szString[pT->_nMaxMenuItemTextLength];
+ for(int i = 0; i < nItems; i++)
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU;
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = szString;
+ mii.cch = pT->_nMaxMenuItemTextLength;
+ BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii);
+ ATLASSERT(bRet);
+ // If we have more than the buffer, we assume we have bitmaps bits
+ if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1)
+ {
+ mii.fType = MFT_BITMAP;
+ ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii);
+ szString[0] = 0;
+ }
+
+ // NOTE: Command Bar currently supports only drop-down menu items
+ ATLASSERT(mii.hSubMenu != NULL);
+
+ TBBUTTON btn = { 0 };
+ btn.iBitmap = 0;
+ btn.idCommand = i;
+ btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0);
+ btn.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN;
+ btn.dwData = 0;
+ btn.iString = 0;
+
+ bRet = InsertButton(-1, &btn);
+ ATLASSERT(bRet);
+
+ TBBUTTONINFO bi = { 0 };
+ bi.cbSize = sizeof(TBBUTTONINFO);
+ bi.dwMask = TBIF_TEXT;
+ bi.pszText = szString;
+
+ bRet = SetButtonInfo(i, &bi);
+ ATLASSERT(bRet);
+ }
+ }
+
+ SetRedraw(TRUE);
+ Invalidate();
+ UpdateWindow();
+
+ return TRUE;
+ }
+
+ BOOL LoadImages(ATL::_U_STRINGorID image)
+ {
+ return _LoadImagesHelper(image, false);
+ }
+
+ BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
+ {
+ return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize);
+ }
+
+ BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HINSTANCE hInstance = ModuleHelper::GetResourceInstance();
+
+ HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR);
+ if(hRsrc == NULL)
+ return FALSE;
+
+ HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc);
+ if(hGlobal == NULL)
+ return FALSE;
+
+ _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal);
+ if(pData == NULL)
+ return FALSE;
+ ATLASSERT(pData->wVersion == 1);
+
+ WORD* pItems = pData->items();
+ int nItems = pData->wItemCount;
+
+ // Set internal data
+ SetImageSize(pData->wWidth, pData->wHeight);
+
+ // Create image list if needed
+ if(m_hImageList == NULL)
+ {
+ // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only)
+ T* pT = static_cast<T*>(this);
+ m_bAlphaImages = AtlIsAlphaBitmapResource(image);
+
+ if(!pT->CreateInternalImageList(pData->wItemCount))
+ return FALSE;
+ }
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ int nOldImageCount = ::ImageList_GetImageCount(m_hImageList);
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+ // Add bitmap to our image list
+ CBitmap bmp;
+ if(bMapped)
+ {
+ ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0); // if mapped, must be a numeric ID
+ int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr));
+ bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize);
+ }
+ else
+ {
+ if(m_bAlphaImages)
+ bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+ else
+ bmp.LoadBitmap(image.m_lpstr);
+ }
+ ATLASSERT(bmp.m_hBitmap != NULL);
+ if(bmp.m_hBitmap == NULL)
+ return FALSE;
+ if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1)
+ return FALSE;
+
+ // Fill the array with command IDs
+ for(int i = 0; i < nItems; i++)
+ {
+ if(pItems[i] != 0)
+ m_arrCommand.Add(pItems[i]);
+ }
+
+ int nImageCount = ::ImageList_GetImageCount(m_hImageList);
+ ATLASSERT(nImageCount == m_arrCommand.GetSize());
+ if(nImageCount != m_arrCommand.GetSize())
+ return FALSE;
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista())
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount);
+ ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize());
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+ return TRUE;
+ }
+
+ BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ CBitmap bmp;
+ bmp.LoadBitmap(bitmap.m_lpstr);
+ if(bmp.m_hBitmap == NULL)
+ return FALSE;
+ return AddBitmap(bmp, nCommandID);
+ }
+
+ BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ // Create image list if it doesn't exist
+ if(m_hImageList == NULL)
+ {
+ if(!pT->CreateInternalImageList(1))
+ return FALSE;
+ }
+ // check bitmap size
+ CBitmapHandle bmp = hBitmap;
+ SIZE size = { 0, 0 };
+ bmp.GetSize(size);
+ if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy)
+ {
+ ATLASSERT(FALSE); // must match size!
+ return FALSE;
+ }
+ // add bitmap
+ int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask);
+ if(nRet == -1)
+ return FALSE;
+ BOOL bRet = m_arrCommand.Add((WORD)nCommandID);
+ ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista())
+ {
+ pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);
+ ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ return bRet;
+ }
+
+ BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
+ if(hIcon == NULL)
+ return FALSE;
+ return AddIcon(hIcon, nCommandID);
+ }
+
+ BOOL AddIcon(HICON hIcon, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ // create image list if it doesn't exist
+ if(m_hImageList == NULL)
+ {
+ if(!pT->CreateInternalImageList(1))
+ return FALSE;
+ }
+
+ int nRet = ::ImageList_AddIcon(m_hImageList, hIcon);
+ if(nRet == -1)
+ return FALSE;
+ BOOL bRet = m_arrCommand.Add((WORD)nCommandID);
+ ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista())
+ {
+ pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);
+ ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ return bRet;
+ }
+
+ BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ CBitmap bmp;
+ bmp.LoadBitmap(bitmap.m_lpstr);
+ if(bmp.m_hBitmap == NULL)
+ return FALSE;
+ return ReplaceBitmap(bmp, nCommandID);
+ }
+
+ BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ BOOL bRet = FALSE;
+ for(int i = 0; i < m_arrCommand.GetSize(); i++)
+ {
+ if(m_arrCommand[i] == nCommandID)
+ {
+ bRet = ::ImageList_Remove(m_hImageList, i);
+ if(bRet)
+ {
+ m_arrCommand.RemoveAt(i);
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista())
+ {
+ if(m_arrVistaBitmap[i] != NULL)
+ ::DeleteObject(m_arrVistaBitmap[i]);
+ m_arrVistaBitmap.RemoveAt(i);
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ }
+ break;
+ }
+ }
+ if(bRet)
+ bRet = AddBitmap(hBitmap, nCommandID);
+ return bRet;
+ }
+
+ BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
+ if(hIcon == NULL)
+ return FALSE;
+ return ReplaceIcon(hIcon, nCommandID);
+ }
+
+ BOOL ReplaceIcon(HICON hIcon, UINT nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ BOOL bRet = FALSE;
+ for(int i = 0; i < m_arrCommand.GetSize(); i++)
+ {
+ if(m_arrCommand[i] == nCommandID)
+ {
+ bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1);
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista() && bRet != FALSE)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_ReplaceVistaBitmapFromImageList(i);
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ break;
+ }
+ }
+ return bRet;
+ }
+
+ BOOL RemoveImage(int nCommandID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ BOOL bRet = FALSE;
+ for(int i = 0; i < m_arrCommand.GetSize(); i++)
+ {
+ if(m_arrCommand[i] == nCommandID)
+ {
+ bRet = ::ImageList_Remove(m_hImageList, i);
+ if(bRet)
+ {
+ m_arrCommand.RemoveAt(i);
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(RunTimeHelper::IsVista())
+ {
+ if(m_arrVistaBitmap[i] != NULL)
+ ::DeleteObject(m_arrVistaBitmap[i]);
+ m_arrVistaBitmap.RemoveAt(i);
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ }
+ break;
+ }
+ }
+ return bRet;
+ }
+
+ BOOL RemoveAllImages()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n"));
+ BOOL bRet = ::ImageList_RemoveAll(m_hImageList);
+ if(bRet)
+ {
+ m_arrCommand.RemoveAll();
+#if _WTL_CMDBAR_VISTA_MENUS
+ for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)
+ {
+ if(m_arrVistaBitmap[i] != NULL)
+ ::DeleteObject(m_arrVistaBitmap[i]);
+ }
+ m_arrVistaBitmap.RemoveAll();
+#endif // _WTL_CMDBAR_VISTA_MENUS
+ }
+ return bRet;
+ }
+
+ BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(::IsMenu(hMenu));
+ if(!::IsMenu(hMenu))
+ return FALSE;
+ m_bContextMenu = true;
+ if(m_bUseKeyboardCues)
+ m_bShowKeyboardCues = m_bKeyboardInput;
+ T* pT = static_cast<T*>(this);
+ return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams);
+ }
+
+ BOOL SetMDIClient(HWND /*hWndMDIClient*/)
+ {
+ // Use CMDICommandBarCtrl for MDI support
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CCommandBarCtrlImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_INITMENU, OnInitMenu)
+ MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
+ MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
+ MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup)
+ MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+ MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)
+
+ MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
+ MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
+ MESSAGE_HANDLER(WM_CHAR, OnChar)
+ MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)
+ MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)
+ MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)
+// public API handlers - these stay to support chevrons in atlframe.h
+ MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu)
+ MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu)
+ MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar)
+
+ MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
+ MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
+
+ MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)
+ ALT_MSG_MAP(1) // Parent window messages
+ NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange)
+ NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown)
+ MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup)
+ MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar)
+ MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand)
+ MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu)
+ MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar)
+ MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu)
+ MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange)
+
+ MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem)
+ MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem)
+
+ MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)
+ NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw)
+ ALT_MSG_MAP(2) // MDI client window messages
+ // Use CMDICommandBarCtrl for MDI support
+ ALT_MSG_MAP(3) // Message hook messages
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove)
+ MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown)
+ MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp)
+ MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar)
+ MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown)
+ MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu)
+ MESSAGE_HANDLER(WM_CHAR, OnHookChar)
+ END_MSG_MAP()
+
+ LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LPMSG pMsg = (LPMSG)lParam;
+ if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)
+ m_bKeyboardInput = false;
+ else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
+ m_bKeyboardInput = true;
+ LRESULT lRet = 0;
+ ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3);
+ return lRet;
+ }
+
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ // Let the toolbar initialize itself
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ // get and use system settings
+ T* pT = static_cast<T*>(this);
+ pT->GetSystemSettings();
+ // Parent init
+ ATL::CWindow wndParent = GetParent();
+ ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent();
+ m_wndParent.SubclassWindow(wndTopLevelParent);
+ // Toolbar Init
+ SetButtonStructSize();
+ SetImageList(NULL);
+
+ // Create message hook if needed
+ CWindowCreateCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n"));
+ ATLASSERT(FALSE);
+ return -1;
+ }
+
+ if(s_pmapMsgHook == NULL)
+ {
+ ATLTRY(s_pmapMsgHook = new CMsgHookMap);
+ ATLASSERT(s_pmapMsgHook != NULL);
+ }
+
+ if(s_pmapMsgHook != NULL)
+ {
+ DWORD dwThreadID = ::GetCurrentThreadId();
+ _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
+ if(pData == NULL)
+ {
+ ATLTRY(pData = new _MsgHookData);
+ ATLASSERT(pData != NULL);
+ HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID);
+ ATLASSERT(hMsgHook != NULL);
+ if(pData != NULL && hMsgHook != NULL)
+ {
+ pData->hMsgHook = hMsgHook;
+ pData->dwUsage = 1;
+ BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData);
+ bRet;
+ ATLASSERT(bRet);
+ }
+ }
+ else
+ {
+ (pData->dwUsage)++;
+ }
+ }
+ lock.Unlock();
+
+ // Get layout
+#if (WINVER >= 0x0500)
+ m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0);
+#endif // (WINVER >= 0x0500)
+
+ return lRet;
+ }
+
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ if(m_bVistaMenus && (m_hMenu != NULL))
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_RemoveVistaBitmapsFromMenu();
+ }
+
+ for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)
+ {
+ if(m_arrVistaBitmap[i] != NULL)
+ ::DeleteObject(m_arrVistaBitmap[i]);
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+ if(m_bAttachedMenu) // nothing to do in this mode
+ return lRet;
+
+ CWindowCreateCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n"));
+ ATLASSERT(FALSE);
+ return lRet;
+ }
+
+ if(s_pmapMsgHook != NULL)
+ {
+ DWORD dwThreadID = ::GetCurrentThreadId();
+ _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
+ if(pData != NULL)
+ {
+ (pData->dwUsage)--;
+ if(pData->dwUsage == 0)
+ {
+ BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook);
+ ATLASSERT(bRet);
+ bRet = s_pmapMsgHook->Remove(dwThreadID);
+ ATLASSERT(bRet);
+ if(bRet)
+ delete pData;
+ }
+
+ if(s_pmapMsgHook->GetSize() == 0)
+ {
+ delete s_pmapMsgHook;
+ s_pmapMsgHook = NULL;
+ }
+ }
+ }
+
+ lock.Unlock();
+
+ return lRet;
+ }
+
+ LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n"));
+#endif
+ bHandled = FALSE;
+ // Simulate Alt+Space for the parent
+ if(wParam == VK_SPACE)
+ {
+ m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29));
+ bHandled = TRUE;
+ }
+#if (_WIN32_IE >= 0x0500)
+ else if(wParam == VK_LEFT || wParam == VK_RIGHT)
+ {
+ WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;
+
+ if(!m_bMenuActive)
+ {
+ T* pT = static_cast<T*>(this);
+ int nBtn = GetHotItem();
+ int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn);
+ if(nNextBtn == -2)
+ {
+ SetHotItem(-1);
+ if(pT->DisplayChevronMenu())
+ bHandled = TRUE;
+ }
+ }
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ return 0;
+ }
+
+ LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n"));
+#endif
+ if(wParam != VK_SPACE)
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n"));
+#endif
+ if(wParam != VK_SPACE)
+ bHandled = FALSE;
+ else
+ return 0;
+ // Security
+ if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd)
+ return 0;
+
+ // Handle mnemonic press when we have focus
+ int nBtn = 0;
+ if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn))
+ {
+#if (_WIN32_IE >= 0x0500)
+ if((TCHAR)LOWORD(wParam) != _chChevronShortcut)
+#endif // (_WIN32_IE >= 0x0500)
+ ::MessageBeep(0);
+ }
+ else
+ {
+#if (_WIN32_IE >= 0x0500)
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ RECT rcBtn = { 0 };
+ GetItemRect(nBtn, &rcBtn);
+ TBBUTTON tbb = { 0 };
+ GetButton(nBtn, &tbb);
+ if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)
+ {
+#endif // (_WIN32_IE >= 0x0500)
+ PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
+ if(wParam != VK_RETURN)
+ SetHotItem(nBtn);
+#if (_WIN32_IE >= 0x0500)
+ }
+ else
+ {
+ ::MessageBeep(0);
+ bHandled = TRUE;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ }
+ return 0;
+ }
+
+ LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n"));
+#endif
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n"));
+#endif
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n"));
+#endif
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT))
+ {
+ bHandled = FALSE;
+ return 0;
+ }
+
+ CDCHandle dc = (HDC)wParam;
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+ dc.FillRect(&rect, COLOR_MENU);
+
+ return 1; // don't do the default erase
+ }
+
+ LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ int nIndex = GetHotItem();
+ SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu);
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ if((BOOL)HIWORD(lParam)) // System menu, do nothing
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ if(!(m_bAttachedMenu || m_bMenuActive)) // Not attached or ours, do nothing
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n"));
+#endif
+ // forward to the parent or subclassed window, so it can handle update UI
+ LRESULT lRet = 0;
+ if(m_bAttachedMenu)
+ lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());
+ else
+ lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ // If Vista menus are active, just set bitmaps and return
+ if(m_bVistaMenus)
+ {
+ CMenuHandle menu = (HMENU)wParam;
+ ATLASSERT(menu.m_hMenu != NULL);
+
+ for(int i = 0; i < menu.GetMenuItemCount(); i++)
+ {
+ WORD nID = (WORD)menu.GetMenuItemID(i);
+ int nIndex = m_arrCommand.Find(nID);
+
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_BITMAP;
+ mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL;
+ menu.SetMenuItemInfo(i, TRUE, &mii);
+ }
+
+ return lRet;
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+ // Convert menu items to ownerdraw, add our data
+ if(m_bImagesVisible)
+ {
+ CMenuHandle menuPopup = (HMENU)wParam;
+ ATLASSERT(menuPopup.m_hMenu != NULL);
+
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ TCHAR szString[pT->_nMaxMenuItemTextLength];
+ BOOL bRet = FALSE;
+ for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
+ {
+ CMenuItemInfo mii;
+ mii.cch = pT->_nMaxMenuItemTextLength;
+ mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
+ mii.dwTypeData = szString;
+ bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+
+ if(!(mii.fType & MFT_OWNERDRAW)) // Not already an ownerdraw item
+ {
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
+ _MenuItemData* pMI = NULL;
+ ATLTRY(pMI = new _MenuItemData);
+ ATLASSERT(pMI != NULL);
+ if(pMI != NULL)
+ {
+ pMI->fType = mii.fType;
+ pMI->fState = mii.fState;
+ mii.fType |= MFT_OWNERDRAW;
+ pMI->iButton = -1;
+ for(int j = 0; j < m_arrCommand.GetSize(); j++)
+ {
+ if(m_arrCommand[j] == mii.wID)
+ {
+ pMI->iButton = j;
+ break;
+ }
+ }
+ int cchLen = lstrlen(szString) + 1;
+ pMI->lpstrText = NULL;
+ ATLTRY(pMI->lpstrText = new TCHAR[cchLen]);
+ ATLASSERT(pMI->lpstrText != NULL);
+ if(pMI->lpstrText != NULL)
+ SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString);
+ mii.dwItemData = (ULONG_PTR)pMI;
+ bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+ }
+ }
+ }
+
+ // Add it to the list
+ m_stackMenuHandle.Push(menuPopup.m_hMenu);
+ }
+
+ return lRet;
+ }
+
+ LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bAttachedMenu) // Not attached, do nothing, forward to parent
+ {
+ m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP);
+ if(m_wndParent.IsWindow())
+ m_wndParent.SendMessage(uMsg, wParam, lParam);
+ bHandled = FALSE;
+ return 1;
+ }
+
+ // Check if a menu is closing, do a cleanup
+ if(HIWORD(wParam) == 0xFFFF && lParam == NULL) // Menu closing
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n"));
+#endif
+ ATLASSERT(m_stackMenuWnd.GetSize() == 0);
+ // Restore the menu items to the previous state for all menus that were converted
+ if(m_bImagesVisible)
+ {
+ HMENU hMenu = NULL;
+ while((hMenu = m_stackMenuHandle.Pop()) != NULL)
+ {
+ CMenuHandle menuPopup = hMenu;
+ ATLASSERT(menuPopup.m_hMenu != NULL);
+ // Restore state and delete menu item data
+ BOOL bRet = FALSE;
+ for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_DATA | MIIM_TYPE;
+ bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+
+ _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;
+ if(pMI != NULL && pMI->IsCmdBarMenuItem())
+ {
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
+ mii.fType = pMI->fType;
+ mii.dwTypeData = pMI->lpstrText;
+ mii.cch = lstrlen(pMI->lpstrText);
+ mii.dwItemData = NULL;
+
+ bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+
+ delete [] pMI->lpstrText;
+ pMI->dwMagic = 0x6666;
+ delete pMI;
+ }
+ }
+ }
+ }
+ }
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ int nIndex = (int)wParam;
+ T* pT = static_cast<T*>(this);
+ pT->DoPopupMenu(nIndex, false);
+ return 0;
+ }
+
+ LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ // Let's make sure we're not embedded in another process
+ if((LPVOID)wParam != NULL)
+ *((DWORD*)wParam) = GetCurrentProcessId();
+ if(IsWindowVisible())
+ return (LRESULT)static_cast<CCommandBarCtrlBase*>(this);
+ else
+ return NULL;
+ }
+
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+#ifndef SPI_GETKEYBOARDCUES
+ const UINT SPI_SETKEYBOARDCUES = 0x100B;
+#endif // !SPI_GETKEYBOARDCUES
+#ifndef SPI_GETFLATMENU
+ const UINT SPI_SETFLATMENU = 0x1023;
+#endif // !SPI_GETFLATMENU
+
+ if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->GetSystemSettings();
+ }
+
+ return 0;
+ }
+
+ LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+
+ LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;
+ int cyMin = ::GetSystemMetrics(SM_CYMENU);
+ if(lpWP->cy < cyMin)
+ lpWP->cy = cyMin;
+
+ return lRet;
+ }
+
+ LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n"));
+#endif
+ bHandled = TRUE;
+ T* pT = static_cast<T*>(this);
+
+ LRESULT lRet;
+ if(m_bMenuActive && LOWORD(wParam) != 0x0D)
+ lRet = 0;
+ else
+ lRet = MAKELRESULT(1, 1);
+
+ if(m_bMenuActive && HIWORD(wParam) == MF_POPUP)
+ {
+ // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout
+ TCHAR ch = (TCHAR)LOWORD(wParam);
+ CMenuHandle menu = (HMENU)lParam;
+ int nCount = ::GetMenuItemCount(menu);
+ int nRetCode = MNC_EXECUTE;
+ BOOL bRet = FALSE;
+ TCHAR szString[pT->_nMaxMenuItemTextLength];
+ WORD wMnem = 0;
+ bool bFound = false;
+ for(int i = 0; i < nCount; i++)
+ {
+ CMenuItemInfo mii;
+ mii.cch = pT->_nMaxMenuItemTextLength;
+ mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
+ mii.dwTypeData = szString;
+ bRet = menu.GetMenuItemInfo(i, TRUE, &mii);
+ if(!bRet || (mii.fType & MFT_SEPARATOR))
+ continue;
+ _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData;
+ if(pmd != NULL && pmd->IsCmdBarMenuItem())
+ {
+ LPTSTR p = pmd->lpstrText;
+
+ if(p != NULL)
+ {
+ while(*p && *p != _T('&'))
+ p = ::CharNext(p);
+ if(p != NULL && *p)
+ {
+ DWORD dwP = MAKELONG(*(++p), 0);
+ DWORD dwC = MAKELONG(ch, 0);
+ if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC)))
+ {
+ if(!bFound)
+ {
+ wMnem = (WORD)i;
+ bFound = true;
+ }
+ else
+ {
+ nRetCode = MNC_SELECT;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if(bFound)
+ {
+ if(nRetCode == MNC_EXECUTE)
+ {
+ PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
+ pT->GiveFocusBack();
+ }
+ bHandled = TRUE;
+ lRet = MAKELRESULT(wMnem, nRetCode);
+ }
+ }
+ else if(!m_bMenuActive)
+ {
+ int nBtn = 0;
+ if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn))
+ {
+ bHandled = FALSE;
+ PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
+ pT->GiveFocusBack();
+
+#if (_WIN32_IE >= 0x0500)
+ // check if we should display chevron menu
+ if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut)
+ {
+ if(pT->DisplayChevronMenu())
+ bHandled = TRUE;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ }
+ else if(m_wndParent.IsWindowEnabled())
+ {
+#if (_WIN32_IE >= 0x0500)
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ RECT rcBtn = { 0 };
+ GetItemRect(nBtn, &rcBtn);
+ TBBUTTON tbb = { 0 };
+ GetButton(nBtn, &tbb);
+ if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)
+ {
+#endif // (_WIN32_IE >= 0x0500)
+ if(m_bUseKeyboardCues && !m_bShowKeyboardCues)
+ {
+ m_bAllowKeyboardCues = true;
+ ShowKeyboardCues(true);
+ }
+ pT->TakeFocus();
+ PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
+ SetHotItem(nBtn);
+#if (_WIN32_IE >= 0x0500)
+ }
+ else
+ {
+ ::MessageBeep(0);
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ }
+ }
+
+ return lRet;
+ }
+
+ LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam;
+ _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
+ if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())
+ {
+ T* pT = static_cast<T*>(this);
+ pT->DrawItem(lpDrawItemStruct);
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+ return (LRESULT)TRUE;
+ }
+
+ LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;
+ _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;
+ if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())
+ {
+ T* pT = static_cast<T*>(this);
+ pT->MeasureItem(lpMeasureItemStruct);
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+ return (LRESULT)TRUE;
+ }
+
+// API message handlers
+ LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)m_hMenu;
+ }
+
+ LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(lParam == NULL)
+ return FALSE;
+ LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam;
+ if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU))
+ return FALSE;
+
+ T* pT = static_cast<T*>(this);
+ return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm);
+ }
+
+ LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)m_hWnd;
+ }
+
+// Parent window message handlers
+ LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh;
+
+ // Check if this comes from us
+ if(pnmh->hwndFrom != m_hWnd)
+ {
+ bHandled = FALSE;
+ return 0;
+ }
+
+ bool bBlockTracking = false;
+ if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0)
+ {
+ DWORD dwProcessID;
+ ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID);
+ bBlockTracking = (::GetCurrentProcessId() != dwProcessID);
+ }
+
+ if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE))
+ {
+ return 1;
+ }
+ else
+ {
+#ifndef HICF_LMOUSE
+ const DWORD HICF_LMOUSE = 0x00000080; // left mouse button selected
+#endif
+ bHandled = FALSE;
+
+ // Send WM_MENUSELECT to the app if it needs to display a status text
+ if(!(lpNMHT->dwFlags & HICF_MOUSE)
+ && !(lpNMHT->dwFlags & HICF_ACCELERATOR)
+ && !(lpNMHT->dwFlags & HICF_LMOUSE))
+ {
+ if(lpNMHT->dwFlags & HICF_ENTERING)
+ m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu);
+ if(lpNMHT->dwFlags & HICF_LEAVING)
+ m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL);
+ }
+
+ return 0;
+ }
+ }
+
+ LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ // Check if this comes from us
+ if(pnmh->hwndFrom != m_hWnd)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ T* pT = static_cast<T*>(this);
+ if(::GetFocus() != m_hWnd)
+ pT->TakeFocus();
+ LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh;
+ int nIndex = CommandToIndex(pNMToolBar->iItem);
+ m_bContextMenu = false;
+ m_bEscapePressed = false;
+ pT->DoPopupMenu(nIndex, true);
+
+ return TBDDRET_DEFAULT;
+ }
+
+ LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnInitMenuPopup(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnInternalGetBar(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+ if((m_uSysKey == VK_MENU
+ || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80))
+ || m_uSysKey == VK_SPACE)
+ && wParam == SC_KEYMENU)
+ {
+ T* pT = static_cast<T*>(this);
+ if(::GetFocus() == m_hWnd)
+ {
+ pT->GiveFocusBack(); // exit menu "loop"
+ PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
+ }
+ else if(m_uSysKey != VK_SPACE && !m_bSkipMsg)
+ {
+ if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)
+ ShowKeyboardCues(true);
+
+ pT->TakeFocus(); // enter menu "loop"
+ bHandled = TRUE;
+ }
+ else if(m_uSysKey != VK_SPACE)
+ {
+ bHandled = TRUE;
+ }
+ }
+ m_bSkipMsg = false;
+ return 0;
+ }
+
+ LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnAPIGetMenu(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnMenuChar(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ OnSettingChange(uMsg, wParam, lParam, bHandled);
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnDrawItem(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ return OnMeasureItem(uMsg, wParam, lParam, bHandled);
+ }
+
+ LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);
+ if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues)
+ {
+ ShowKeyboardCues(false); // this will repaint our window
+ }
+ else
+ {
+ Invalidate();
+ UpdateWindow();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ LRESULT lRet = CDRF_DODEFAULT;
+ bHandled = FALSE;
+ if(pnmh->hwndFrom == m_hWnd)
+ {
+ LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh;
+ if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
+ {
+ lRet = CDRF_NOTIFYITEMDRAW;
+ bHandled = TRUE;
+ }
+ else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
+ {
+ if(m_bFlatMenus)
+ {
+#ifndef COLOR_MENUHILIGHT
+ const int COLOR_MENUHILIGHT = 29;
+#endif // !COLOR_MENUHILIGHT
+ bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED);
+ if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT ||
+ (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED))
+ {
+ ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT));
+ ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));
+ lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT);
+ }
+ else if(bDisabled || !m_bParentActive)
+ {
+ lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);
+ }
+ CDCHandle dc = lpTBCustomDraw->nmcd.hdc;
+ dc.SetTextColor(lpTBCustomDraw->clrText);
+ dc.SetBkMode(lpTBCustomDraw->nStringBkMode);
+ HFONT hFont = GetFont();
+ HFONT hFontOld = NULL;
+ if(hFont != NULL)
+ hFontOld = dc.SelectFont(hFont);
+ const int cchText = 200;
+ TCHAR szText[cchText] = { 0 };
+ TBBUTTONINFO tbbi = { 0 };
+ tbbi.cbSize = sizeof(TBBUTTONINFO);
+ tbbi.dwMask = TBIF_TEXT;
+ tbbi.pszText = szText;
+ tbbi.cchText = cchText;
+ GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi);
+ dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
+ if(hFont != NULL)
+ dc.SelectFont(hFontOld);
+ lRet = CDRF_SKIPDEFAULT;
+ bHandled = TRUE;
+ }
+ else if(!m_bParentActive)
+ {
+ lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);
+ bHandled = TRUE;
+ }
+ }
+ }
+ return lRet;
+ }
+
+// Message hook handlers
+ LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ static POINT s_point = { -1, -1 };
+ DWORD dwPoint = ::GetMessagePos();
+ POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) };
+
+ bHandled = FALSE;
+ if(m_bMenuActive)
+ {
+ if(::WindowFromPoint(point) == m_hWnd)
+ {
+ ScreenToClient(&point);
+ int nHit = HitTest(&point);
+
+ if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1)
+ {
+ TBBUTTON tbb = { 0 };
+ GetButton(nHit, &tbb);
+ if((tbb.fsState & TBSTATE_ENABLED) != 0)
+ {
+ m_nNextPopBtn = nHit | 0xFFFF0000;
+ HWND hWndMenu = m_stackMenuWnd.GetCurrent();
+ ATLASSERT(hWndMenu != NULL);
+
+ // this one is needed to close a menu if mouse button was down
+ ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y));
+ // this one closes a popup menu
+ ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
+
+ bHandled = TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ ScreenToClient(&point);
+ }
+
+ s_point = point;
+ return 0;
+ }
+
+ LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam);
+#endif
+
+ if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)
+ ShowKeyboardCues(true);
+
+ if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd)
+ {
+ m_bAllowKeyboardCues = false;
+ PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
+ T* pT = static_cast<T*>(this);
+ pT->GiveFocusBack();
+ m_bSkipMsg = true;
+ }
+ else
+ {
+ if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues)
+ {
+ m_bAllowKeyboardCues = true;
+ ShowKeyboardCues(false);
+ }
+ m_uSysKey = (UINT)wParam;
+ }
+ return 0;
+ }
+
+ LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(!m_bAllowKeyboardCues)
+ m_bAllowKeyboardCues = true;
+ bHandled = FALSE;
+ wParam;
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam);
+#endif
+ return 0;
+ }
+
+ LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam);
+#endif
+
+ if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE)
+ bHandled = TRUE;
+ return 0;
+ }
+
+ LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam);
+#endif
+ bHandled = FALSE;
+ T* pT = static_cast<T*>(this);
+
+ if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1)
+ {
+ if(m_bMenuActive && !m_bContextMenu)
+ {
+ int nHot = GetHotItem();
+ if(nHot == -1)
+ nHot = m_nPopBtn;
+ if(nHot == -1)
+ nHot = 0;
+ SetHotItem(nHot);
+ bHandled = TRUE;
+ pT->TakeFocus();
+ m_bEscapePressed = true; // To keep focus
+ m_bSkipPostDown = false;
+ }
+ else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow())
+ {
+ SetHotItem(-1);
+ pT->GiveFocusBack();
+ bHandled = TRUE;
+ }
+ }
+ else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN)
+ {
+ if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow())
+ {
+ int nHot = GetHotItem();
+ if(nHot != -1)
+ {
+ if(wParam != VK_RETURN)
+ {
+ if(!m_bSkipPostDown)
+ {
+// IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click
+#if (_WIN32_IE < 0x0500)
+ DWORD dwMajor = 0, dwMinor = 0;
+ ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
+ if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80))
+ {
+ RECT rect;
+ GetItemRect(nHot, &rect);
+ PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top));
+ }
+#endif // (_WIN32_IE < 0x0500)
+ PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
+ m_bSkipPostDown = true;
+ }
+ else
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n"));
+ m_bSkipPostDown = false;
+ }
+ }
+ }
+ else
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n"));
+ }
+ }
+ if(wParam == VK_RETURN && m_bMenuActive)
+ {
+ PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
+ m_nNextPopBtn = -1;
+ pT->GiveFocusBack();
+ }
+ }
+ else if(wParam == VK_LEFT || wParam == VK_RIGHT)
+ {
+ WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;
+ WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT;
+
+ if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem))
+ {
+ bool bAction = false;
+ if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1)
+ {
+ m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn);
+ if(m_nNextPopBtn != -1)
+ bAction = true;
+ }
+ else if(wParam == wpNext)
+ {
+ m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn);
+ if(m_nNextPopBtn != -1)
+ bAction = true;
+ }
+ HWND hWndMenu = m_stackMenuWnd.GetCurrent();
+ ATLASSERT(hWndMenu != NULL);
+
+ // Close the popup menu
+ if(bAction)
+ {
+ ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
+ if(wParam == wpNext)
+ {
+ int cItem = m_stackMenuWnd.GetSize() - 1;
+ while(cItem >= 0)
+ {
+ hWndMenu = m_stackMenuWnd[cItem];
+ if(hWndMenu != NULL)
+ ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
+ cItem--;
+ }
+ }
+#if (_WIN32_IE >= 0x0500)
+ if(m_nNextPopBtn == -2)
+ {
+ m_nNextPopBtn = -1;
+ pT->DisplayChevronMenu();
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ bHandled = TRUE;
+ }
+ }
+ }
+ return 0;
+ }
+
+ LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n"));
+#endif
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam);
+#endif
+ bHandled = (wParam == VK_ESCAPE);
+ return 0;
+ }
+
+// Implementation - ownerdraw overrideables and helpers
+ void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+ {
+ T* pT = static_cast<T*>(this);
+ if(m_bFlatMenus)
+ pT->DrawItemFlat(lpDrawItemStruct);
+ else
+ pT->DrawItem3D(lpDrawItemStruct);
+
+ }
+
+ void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct)
+ {
+ _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
+ CDCHandle dc = lpDrawItemStruct->hDC;
+ const RECT& rcItem = lpDrawItemStruct->rcItem;
+ T* pT = static_cast<T*>(this);
+
+ if(pmd->fType & MFT_SEPARATOR)
+ {
+ // draw separator
+ RECT rc = rcItem;
+ rc.top += (rc.bottom - rc.top) / 2; // vertical center
+ dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
+ }
+ else // not a separator
+ {
+ BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;
+ BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;
+ BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;
+ BOOL bHasImage = FALSE;
+
+ if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)
+ bSelected = FALSE;
+ RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect
+ ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically
+
+ int iButton = pmd->iButton;
+ if(iButton >= 0)
+ {
+ bHasImage = TRUE;
+
+ // calc drawing point
+ SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };
+ sz.cx /= 2;
+ sz.cy /= 2;
+ POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };
+
+ // fill background depending on state
+ if(!bChecked || (bSelected && !bDisabled))
+ {
+ if(!bDisabled)
+ dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU);
+ else
+ dc.FillRect(&rcButn, COLOR_MENU);
+ }
+ else
+ {
+ COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));
+ COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));
+ CBrush hbr(CDCHandle::GetHalftoneBrush());
+ dc.SetBrushOrg(rcButn.left, rcButn.top);
+ dc.FillRect(&rcButn, hbr);
+ dc.SetTextColor(crTxt);
+ dc.SetBkColor(crBk);
+ }
+
+ // draw disabled or normal
+ if(!bDisabled)
+ {
+ // draw pushed-in or popped-out edge
+ if(bSelected || bChecked)
+ {
+ RECT rc2 = rcButn;
+ dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT);
+ }
+ // draw the image
+ ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);
+ }
+ else
+ {
+ HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU);
+ pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground);
+ }
+ }
+ else
+ {
+ // no image - look for custom checked/unchecked bitmaps
+ CMenuItemInfo info;
+ info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;
+ ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);
+ if(bChecked || info.hbmpUnchecked != NULL)
+ {
+ BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);
+ bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);
+ }
+ }
+
+ // draw item text
+ int cxButn = m_szButton.cx;
+ COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);
+ if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)
+ {
+ RECT rcBG = rcItem;
+ if(bHasImage)
+ rcBG.left += cxButn + s_kcxGap;
+ dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);
+ }
+
+ // calc text rectangle and colors
+ RECT rcText = rcItem;
+ rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;
+ rcText.right -= cxButn;
+ dc.SetBkMode(TRANSPARENT);
+ COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
+
+ // font already selected by Windows
+ if(bDisabled && (!bSelected || colorText == colorBG))
+ {
+ // disabled - draw shadow text shifted down and right 1 pixel (unles selected)
+ RECT rcDisabled = rcText;
+ ::OffsetRect(&rcDisabled, 1, 1);
+ pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT));
+ }
+ pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!
+ }
+ }
+
+ void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct)
+ {
+ _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
+ CDCHandle dc = lpDrawItemStruct->hDC;
+ const RECT& rcItem = lpDrawItemStruct->rcItem;
+ T* pT = static_cast<T*>(this);
+
+#ifndef COLOR_MENUHILIGHT
+ const int COLOR_MENUHILIGHT = 29;
+#endif // !COLOR_MENUHILIGHT
+
+ BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;
+ BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;
+ BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;
+
+ // paint background
+ if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)
+ {
+ if(bSelected)
+ {
+ dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT));
+ dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ else
+ {
+ dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU));
+ }
+ }
+
+ if(pmd->fType & MFT_SEPARATOR)
+ {
+ // draw separator
+ RECT rc = rcItem;
+ rc.top += (rc.bottom - rc.top) / 2; // vertical center
+ dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
+ }
+ else // not a separator
+ {
+ if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)
+ bSelected = FALSE;
+ RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect
+ ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically
+
+ // draw background and border for checked items
+ if(bChecked)
+ {
+ RECT rcCheck = rcButn;
+ ::InflateRect(&rcCheck, -1, -1);
+ if(bSelected)
+ dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU));
+ dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+
+ int iButton = pmd->iButton;
+ if(iButton >= 0)
+ {
+ // calc drawing point
+ SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };
+ sz.cx /= 2;
+ sz.cy /= 2;
+ POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };
+
+ // draw disabled or normal
+ if(!bDisabled)
+ {
+ ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);
+ }
+ else
+ {
+ HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU);
+ HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW);
+ pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage);
+ }
+ }
+ else
+ {
+ // no image - look for custom checked/unchecked bitmaps
+ CMenuItemInfo info;
+ info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;
+ ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);
+ if(bChecked || info.hbmpUnchecked != NULL)
+ {
+ BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);
+ pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);
+ }
+ }
+
+ // draw item text
+ int cxButn = m_szButton.cx;
+ // calc text rectangle and colors
+ RECT rcText = rcItem;
+ rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;
+ rcText.right -= cxButn;
+ dc.SetBkMode(TRANSPARENT);
+ COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
+
+ pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!
+ }
+ }
+
+ void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color)
+ {
+ int nTab = -1;
+ for(int i = 0; i < lstrlen(lpstrText); i++)
+ {
+ if(lpstrText[i] == _T('\t'))
+ {
+ nTab = i;
+ break;
+ }
+ }
+ dc.SetTextColor(color);
+ dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
+ if(nTab != -1)
+ dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
+ }
+
+ void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point,
+ HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),
+ HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),
+ HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))
+ {
+#if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
+ if(m_bAlphaImages)
+ {
+ IMAGELISTDRAWPARAMS ildp = { 0 };
+ ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
+ ildp.himl = m_hImageList;
+ ildp.i = nImage;
+ ildp.hdcDst = dc;
+ ildp.x = point.x;
+ ildp.y = point.y;
+ ildp.cx = 0;
+ ildp.cy = 0;
+ ildp.xBitmap = 0;
+ ildp.yBitmap = 0;
+ ildp.fStyle = ILD_TRANSPARENT;
+ ildp.fState = ILS_SATURATE;
+ ildp.Frame = 0;
+ ::ImageList_DrawIndirect(&ildp);
+ }
+ else
+#endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
+ {
+ // create memory DC
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(dc);
+ // create mono or color bitmap
+ CBitmap bmp;
+ bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy);
+ ATLASSERT(bmp.m_hBitmap != NULL);
+ // draw image into memory DC--fill BG white first
+ HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);
+ dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS);
+ // If white is the text color, we can't use the normal painting since
+ // it would blend with the WHITENESS, but the mask is OK
+ UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL;
+ ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle);
+ dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage);
+ dcMem.SelectBitmap(hBmpOld); // restore
+ }
+ }
+
+ // old name
+ BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)
+ {
+ return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck);
+ }
+
+ BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)
+ {
+ // get checkmark bitmap, if none, use Windows standard
+ SIZE size = { 0, 0 };
+ CBitmapHandle bmp = hBmpCheck;
+ if(hBmpCheck != NULL)
+ {
+ bmp.GetSize(size);
+ }
+ else
+ {
+ size.cx = ::GetSystemMetrics(SM_CXMENUCHECK);
+ size.cy = ::GetSystemMetrics(SM_CYMENUCHECK);
+ bmp.CreateCompatibleBitmap(dc, size.cx, size.cy);
+ ATLASSERT(bmp.m_hBitmap != NULL);
+ }
+ // center bitmap in caller's rectangle
+ RECT rcDest = rc;
+ if((rc.right - rc.left) > size.cx)
+ {
+ rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2;
+ rcDest.right = rcDest.left + size.cx;
+ }
+ if((rc.bottom - rc.top) > size.cy)
+ {
+ rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2;
+ rcDest.bottom = rcDest.top + size.cy;
+ }
+ // paint background
+ if(!m_bFlatMenus)
+ {
+ if(bSelected && !bDisabled)
+ {
+ dc.FillRect(&rcDest, COLOR_MENU);
+ }
+ else
+ {
+ COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));
+ COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));
+ CBrush hbr(CDCHandle::GetHalftoneBrush());
+ dc.SetBrushOrg(rcDest.left, rcDest.top);
+ dc.FillRect(&rcDest, hbr);
+ dc.SetTextColor(clrTextOld);
+ dc.SetBkColor(clrBkOld);
+ }
+ }
+
+ // create source image
+ CDC dcSource;
+ dcSource.CreateCompatibleDC(dc);
+ HBITMAP hBmpOld = dcSource.SelectBitmap(bmp);
+ // set colors
+ const COLORREF clrBlack = RGB(0, 0, 0);
+ const COLORREF clrWhite = RGB(255, 255, 255);
+ COLORREF clrTextOld = dc.SetTextColor(clrBlack);
+ COLORREF clrBkOld = dc.SetBkColor(clrWhite);
+ // create mask
+ CDC dcMask;
+ dcMask.CreateCompatibleDC(dc);
+ CBitmap bmpMask;
+ bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL);
+ HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask);
+
+ // draw the checkmark transparently
+ int cx = rcDest.right - rcDest.left;
+ int cy = rcDest.bottom - rcDest.top;
+ if(hBmpCheck != NULL)
+ {
+ // build mask based on transparent color
+ dcSource.SetBkColor(m_clrMask);
+ dcMask.SetBkColor(clrBlack);
+ dcMask.SetTextColor(clrWhite);
+ dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY);
+ // draw bitmap using the mask
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND);
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);
+ }
+ else
+ {
+ const DWORD ROP_DSno = 0x00BB0226L;
+ const DWORD ROP_DSa = 0x008800C6L;
+ const DWORD ROP_DSo = 0x00EE0086L;
+ const DWORD ROP_DSna = 0x00220326L;
+
+ // draw mask
+ RECT rcSource = { 0, 0, min(size.cx, rc.right - rc.left), min(size.cy, rc.bottom - rc.top) };
+ dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK);
+
+ // draw shadow if disabled
+ if(!m_bFlatMenus && bDisabled)
+ {
+ // offset by one pixel
+ int x = rcDest.left + 1;
+ int y = rcDest.top + 1;
+ // paint source bitmap
+ const int nColor = COLOR_3DHILIGHT;
+ dcSource.FillRect(&rcSource, nColor);
+ // draw checkmark - special case black and white colors
+ COLORREF clrCheck = ::GetSysColor(nColor);
+ if(clrCheck == clrWhite)
+ {
+ dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSno);
+ dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa);
+ }
+ else
+ {
+ if(clrCheck != clrBlack)
+ {
+ ATLASSERT(dcSource.GetTextColor() == clrBlack);
+ ATLASSERT(dcSource.GetBkColor() == clrWhite);
+ dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);
+ }
+ dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSa);
+ dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo);
+ }
+ }
+
+ // paint source bitmap
+ const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT;
+ dcSource.FillRect(&rcSource, nColor);
+ // draw checkmark - special case black and white colors
+ COLORREF clrCheck = ::GetSysColor(nColor);
+ if(clrCheck == clrWhite)
+ {
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSno);
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa);
+ }
+ else
+ {
+ if(clrCheck != clrBlack)
+ {
+ ATLASSERT(dcSource.GetTextColor() == clrBlack);
+ ATLASSERT(dcSource.GetBkColor() == clrWhite);
+ dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);
+ }
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSa);
+ dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo);
+ }
+ }
+ // restore all
+ dc.SetTextColor(clrTextOld);
+ dc.SetBkColor(clrBkOld);
+ dcSource.SelectBitmap(hBmpOld);
+ dcMask.SelectBitmap(hBmpOld1);
+ if(hBmpCheck == NULL)
+ bmp.DeleteObject();
+ // draw pushed-in hilight
+ if(!m_bFlatMenus && !bDisabled)
+ {
+ if(rc.right - rc.left > size.cx)
+ ::InflateRect(&rcDest, 1,1); // inflate checkmark by one pixel all around
+ dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
+ }
+
+ return TRUE;
+ }
+
+ void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+ {
+ _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;
+
+ if(pmd->fType & MFT_SEPARATOR) // separator - use half system height and zero width
+ {
+ lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2;
+ lpMeasureItemStruct->itemWidth = 0;
+ }
+ else
+ {
+ // compute size of text - use DrawText with DT_CALCRECT
+ CWindowDC dc(NULL);
+ CFont fontBold;
+ HFONT hOldFont = NULL;
+ if(pmd->fState & MFS_DEFAULT)
+ {
+ // need bold version of font
+ LOGFONT lf = { 0 };
+ m_fontMenu.GetLogFont(lf);
+ lf.lfWeight += 200;
+ fontBold.CreateFontIndirect(&lf);
+ ATLASSERT(fontBold.m_hFont != NULL);
+ hOldFont = dc.SelectFont(fontBold);
+ }
+ else
+ {
+ hOldFont = dc.SelectFont(m_fontMenu);
+ }
+
+ RECT rcText = { 0, 0, 0, 0 };
+ dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
+ int cx = rcText.right - rcText.left;
+ dc.SelectFont(hOldFont);
+
+ LOGFONT lf = { 0 };
+ m_fontMenu.GetLogFont(lf);
+ int cy = lf.lfHeight;
+ if(cy < 0)
+ cy = -cy;
+ const int cyMargin = 8;
+ cy += cyMargin;
+
+ // height of item is the bigger of these two
+ lpMeasureItemStruct->itemHeight = max(cy, (int)m_szButton.cy);
+
+ // width is width of text plus a bunch of stuff
+ cx += 2 * s_kcxTextMargin; // L/R margin for readability
+ cx += s_kcxGap; // space between button and menu text
+ cx += 2 * m_szButton.cx; // button width (L=button; R=empty margin)
+ cx += m_cxExtraSpacing; // extra between item text and accelerator keys
+
+ // Windows adds 1 to returned value
+ cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1;
+ lpMeasureItemStruct->itemWidth = cx; // done deal
+ }
+ }
+
+// Implementation - Hook procs
+ static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam)
+ {
+ const int cchClassName = 7;
+ TCHAR szClassName[cchClassName] = { 0 };
+
+ if(nCode == HCBT_CREATEWND)
+ {
+ HWND hWndMenu = (HWND)wParam;
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu);
+#endif
+
+ ::GetClassName(hWndMenu, szClassName, cchClassName);
+ if(!lstrcmp(_T("#32768"), szClassName))
+ s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu);
+ }
+ else if(nCode == HCBT_DESTROYWND)
+ {
+ HWND hWndMenu = (HWND)wParam;
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu);
+#endif
+
+ ::GetClassName(hWndMenu, szClassName, cchClassName);
+ if(!lstrcmp(_T("#32768"), szClassName))
+ {
+ ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent());
+ s_pCurrentBar->m_stackMenuWnd.Pop();
+ }
+ }
+
+ return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam);
+ }
+
+ static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)
+ {
+ LPMSG pMsg = (LPMSG)lParam;
+
+ if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG)
+ {
+ CCommandBarCtrlBase* pCmdBar = NULL;
+ HWND hWnd = pMsg->hwnd;
+ DWORD dwPID = 0;
+ while(pCmdBar == NULL && hWnd != NULL)
+ {
+ pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L);
+ hWnd = ::GetParent(hWnd);
+ }
+
+ if(pCmdBar != NULL && dwPID == GetCurrentProcessId())
+ {
+ pCmdBar->m_hWndHook = pMsg->hwnd;
+ ATLASSERT(pCmdBar->IsCommandBarBase());
+
+ if(::IsWindow(pCmdBar->m_hWnd))
+ pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);
+ else
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n"));
+ }
+ }
+
+ LRESULT lRet = 0;
+ ATLASSERT(s_pmapMsgHook != NULL);
+ if(s_pmapMsgHook != NULL)
+ {
+ DWORD dwThreadID = ::GetCurrentThreadId();
+ _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
+ if(pData != NULL)
+ {
+ lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam);
+ }
+ }
+ return lRet;
+ }
+
+// Implementation
+ void DoPopupMenu(int nIndex, bool bAnimate)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false");
+#endif
+
+ // Menu animation flags
+#ifndef TPM_VERPOSANIMATION
+ const UINT TPM_VERPOSANIMATION = 0x1000L;
+#endif
+#ifndef TPM_NOANIMATION
+ const UINT TPM_NOANIMATION = 0x4000L;
+#endif
+ T* pT = static_cast<T*>(this);
+
+ // get popup menu and it's position
+ RECT rect = { 0 };
+ GetItemRect(nIndex, &rect);
+ POINT pt = { rect.left, rect.bottom };
+ MapWindowPoints(NULL, &pt, 1);
+ MapWindowPoints(NULL, &rect);
+ TPMPARAMS TPMParams = { 0 };
+ TPMParams.cbSize = sizeof(TPMPARAMS);
+ TPMParams.rcExclude = rect;
+ HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex);
+ ATLASSERT(hMenuPopup != NULL);
+
+ // get button ID
+ TBBUTTON tbb = { 0 };
+ GetButton(nIndex, &tbb);
+ int nCmdID = tbb.idCommand;
+
+ m_nPopBtn = nIndex; // remember current button's index
+
+ // press button and display popup menu
+ PressButton(nCmdID, TRUE);
+ SetHotItem(nCmdID);
+ pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN |
+ (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams);
+ PressButton(nCmdID, FALSE);
+ if(::GetFocus() != m_hWnd)
+ SetHotItem(-1);
+
+ m_nPopBtn = -1; // restore
+
+ // eat next message if click is on the same button
+ MSG msg = { 0 };
+ if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt))
+ ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
+
+ // check if another popup menu should be displayed
+ if(m_nNextPopBtn != -1)
+ {
+ PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF);
+ if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem)
+ PostMessage(WM_KEYDOWN, VK_DOWN, 0);
+ m_nNextPopBtn = -1;
+ }
+ else
+ {
+ m_bContextMenu = false;
+ // If user didn't hit escape, give focus back
+ if(!m_bEscapePressed)
+ {
+ if(m_bUseKeyboardCues && m_bShowKeyboardCues)
+ m_bAllowKeyboardCues = false;
+ pT->GiveFocusBack();
+ }
+ else
+ {
+ SetHotItem(nCmdID);
+ SetAnchorHighlight(TRUE);
+ }
+ }
+ }
+
+ BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)
+ {
+ CMenuHandle menuPopup = hMenu;
+
+ CWindowCreateCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n"));
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ ATLASSERT(s_hCreateHook == NULL);
+
+ s_pCurrentBar = static_cast<CCommandBarCtrlBase*>(this);
+
+ s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId());
+ ATLASSERT(s_hCreateHook != NULL);
+
+ m_bPopupItem = false;
+ m_bMenuActive = true;
+
+ BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams);
+ m_bMenuActive = false;
+
+ ::UnhookWindowsHookEx(s_hCreateHook);
+
+ s_hCreateHook = NULL;
+ s_pCurrentBar = NULL;
+
+ lock.Unlock();
+
+ // cleanup - convert menus back to original state
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n"));
+#endif
+
+ ATLASSERT(m_stackMenuWnd.GetSize() == 0);
+
+ UpdateWindow();
+ ATL::CWindow wndTL = GetTopLevelParent();
+ wndTL.UpdateWindow();
+
+ // restore the menu items to the previous state for all menus that were converted
+ if(m_bImagesVisible)
+ {
+ HMENU hMenuSav = NULL;
+ while((hMenuSav = m_stackMenuHandle.Pop()) != NULL)
+ {
+ menuPopup = hMenuSav;
+ BOOL bRet = FALSE;
+ // restore state and delete menu item data
+ for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+
+ _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;
+ if(pMI != NULL && pMI->IsCmdBarMenuItem())
+ {
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
+ mii.fType = pMI->fType;
+ mii.fState = pMI->fState;
+ mii.dwTypeData = pMI->lpstrText;
+ mii.cch = lstrlen(pMI->lpstrText);
+ mii.dwItemData = NULL;
+
+ bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
+ // this one triggers WM_MEASUREITEM
+ menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText);
+ ATLASSERT(bRet);
+
+ delete [] pMI->lpstrText;
+ delete pMI;
+ }
+ }
+ }
+ }
+ return bTrackRet;
+ }
+
+ int GetPreviousMenuItem(int nBtn) const
+ {
+ if(nBtn == -1)
+ return -1;
+#if (_WIN32_IE >= 0x0500)
+ RECT rcClient;
+ GetClientRect(&rcClient);
+#endif // (_WIN32_IE >= 0x0500)
+ int nNextBtn;
+ for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--)
+ {
+ if(nNextBtn < 0)
+ nNextBtn = ::GetMenuItemCount(m_hMenu) - 1;
+ TBBUTTON tbb = { 0 };
+ GetButton(nNextBtn, &tbb);
+#if (_WIN32_IE >= 0x0500)
+ RECT rcBtn;
+ GetItemRect(nNextBtn, &rcBtn);
+ if(rcBtn.right > rcClient.right)
+ {
+ nNextBtn = -2; // chevron
+ break;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)
+ break;
+ }
+ return (nNextBtn != nBtn) ? nNextBtn : -1;
+ }
+
+ int GetNextMenuItem(int nBtn) const
+ {
+ if(nBtn == -1)
+ return -1;
+#if (_WIN32_IE >= 0x0500)
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+#endif // (_WIN32_IE >= 0x0500)
+ int nNextBtn = 0;
+ int nCount = ::GetMenuItemCount(m_hMenu);
+ for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++)
+ {
+ if(nNextBtn >= nCount)
+ nNextBtn = 0;
+ TBBUTTON tbb = { 0 };
+ GetButton(nNextBtn, &tbb);
+#if (_WIN32_IE >= 0x0500)
+ RECT rcBtn = { 0 };
+ GetItemRect(nNextBtn, &rcBtn);
+ if(rcBtn.right > rcClient.right)
+ {
+ nNextBtn = -2; // chevron
+ break;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+ if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)
+ break;
+ }
+ return (nNextBtn != nBtn) ? nNextBtn : -1;
+ }
+
+#if (_WIN32_IE >= 0x0500)
+ bool DisplayChevronMenu()
+ {
+ // assume we are in a rebar
+ HWND hWndReBar = GetParent();
+ int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
+ bool bRet = false;
+ for(int i = 0; i < nCount; i++)
+ {
+ REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE };
+ BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi);
+ if(bRetBandInfo && rbbi.hwndChild == m_hWnd)
+ {
+ if((rbbi.fStyle & RBBS_USECHEVRON) != 0)
+ {
+ ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L);
+ PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ }
+ return bRet;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+
+ void GetSystemSettings()
+ {
+ // refresh our font
+ NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
+ ATLASSERT(bRet);
+ if(bRet)
+ {
+ LOGFONT logfont = { 0 };
+ if(m_fontMenu.m_hFont != NULL)
+ m_fontMenu.GetLogFont(logfont);
+ if(logfont.lfHeight != info.lfMenuFont.lfHeight ||
+ logfont.lfWidth != info.lfMenuFont.lfWidth ||
+ logfont.lfEscapement != info.lfMenuFont.lfEscapement ||
+ logfont.lfOrientation != info.lfMenuFont.lfOrientation ||
+ logfont.lfWeight != info.lfMenuFont.lfWeight ||
+ logfont.lfItalic != info.lfMenuFont.lfItalic ||
+ logfont.lfUnderline != info.lfMenuFont.lfUnderline ||
+ logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||
+ logfont.lfCharSet != info.lfMenuFont.lfCharSet ||
+ logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||
+ logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||
+ logfont.lfQuality != info.lfMenuFont.lfQuality ||
+ logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||
+ lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)
+ {
+ HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);
+ ATLASSERT(hFontMenu != NULL);
+ if(hFontMenu != NULL)
+ {
+ if(m_fontMenu.m_hFont != NULL)
+ m_fontMenu.DeleteObject();
+ m_fontMenu.Attach(hFontMenu);
+ SetFont(m_fontMenu);
+ AddStrings(_T("NS\0")); // for proper item height
+ AutoSize();
+ }
+ }
+ }
+
+ // check if we need extra spacing for menu item text
+ CWindowDC dc(m_hWnd);
+ HFONT hFontOld = dc.SelectFont(m_fontMenu);
+ RECT rcText = { 0, 0, 0, 0 };
+ dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
+ if((rcText.right - rcText.left) < 4)
+ {
+ ::SetRectEmpty(&rcText);
+ dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
+ m_cxExtraSpacing = rcText.right - rcText.left;
+ }
+ else
+ {
+ m_cxExtraSpacing = 0;
+ }
+ dc.SelectFont(hFontOld);
+
+ // get Windows version
+ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
+ ::GetVersionEx(&ovi);
+
+ // query keyboard cues mode (Windows 2000 or later)
+ if(ovi.dwMajorVersion >= 5)
+ {
+#ifndef SPI_GETKEYBOARDCUES
+ const UINT SPI_GETKEYBOARDCUES = 0x100A;
+#endif // !SPI_GETKEYBOARDCUES
+ BOOL bRetVal = TRUE;
+ bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0);
+ m_bUseKeyboardCues = (bRet && !bRetVal);
+ m_bAllowKeyboardCues = true;
+ ShowKeyboardCues(!m_bUseKeyboardCues);
+ }
+
+ // query flat menu mode (Windows XP or later)
+ if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))
+ {
+#ifndef SPI_GETFLATMENU
+ const UINT SPI_GETFLATMENU = 0x1022;
+#endif // !SPI_GETFLATMENU
+ BOOL bRetVal = FALSE;
+ bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0);
+ m_bFlatMenus = (bRet && bRetVal);
+ }
+
+#if _WTL_CMDBAR_VISTA_MENUS
+ // check if we should use Vista menus
+ bool bVistaMenus = (RunTimeHelper::IsVista() && RunTimeHelper::IsCommCtrl6() && ((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0));
+
+ if(bVistaMenus)
+ {
+ HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
+ if(hThemeDLL != NULL)
+ {
+ typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)();
+ PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive");
+ ATLASSERT(pfnIsThemeActive != NULL);
+ bVistaMenus = bVistaMenus && (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE);
+
+ typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)();
+ PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed");
+ ATLASSERT(pfnIsAppThemed != NULL);
+ bVistaMenus = bVistaMenus && (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE);
+
+ ::FreeLibrary(hThemeDLL);
+ }
+ }
+
+ if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0))
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_RemoveVistaBitmapsFromMenu();
+ }
+
+ m_bVistaMenus = bVistaMenus;
+#endif // _WTL_CMDBAR_VISTA_MENUS
+
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"),
+ m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false");
+#endif
+ }
+
+// Implementation - alternate focus mode support
+ void TakeFocus()
+ {
+ if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL)
+ m_hWndFocus = ::GetFocus();
+ SetFocus();
+ }
+
+ void GiveFocusBack()
+ {
+ if(m_bParentActive)
+ {
+ if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus))
+ ::SetFocus(m_hWndFocus);
+ else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow())
+ m_wndParent.SetFocus();
+ }
+ m_hWndFocus = NULL;
+ SetAnchorHighlight(FALSE);
+ if(m_bUseKeyboardCues && m_bShowKeyboardCues)
+ ShowKeyboardCues(false);
+ m_bSkipPostDown = false;
+ }
+
+ void ShowKeyboardCues(bool bShow)
+ {
+ m_bShowKeyboardCues = bShow;
+ SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX);
+ Invalidate();
+ UpdateWindow();
+ }
+
+// Implementation - internal message helpers
+ static UINT GetAutoPopupMessage()
+ {
+ static UINT uAutoPopupMessage = 0;
+ if(uAutoPopupMessage == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uAutoPopupMessage == 0)
+ uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg"));
+
+ lock.Unlock();
+ }
+ ATLASSERT(uAutoPopupMessage != 0);
+ return uAutoPopupMessage;
+ }
+
+ static UINT GetGetBarMessage()
+ {
+ static UINT uGetBarMessage = 0;
+ if(uGetBarMessage == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uGetBarMessage == 0)
+ uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg"));
+
+ lock.Unlock();
+ }
+ ATLASSERT(uGetBarMessage != 0);
+ return uGetBarMessage;
+ }
+
+// Implementation
+ bool CreateInternalImageList(int cImages)
+ {
+ UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK;
+ m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1);
+ ATLASSERT(m_hImageList != NULL);
+ return (m_hImageList != NULL);
+ }
+
+// Implementation - support for Vista menus
+#if _WTL_CMDBAR_VISTA_MENUS
+ void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount)
+ {
+ // Create display compatible memory DC
+ CClientDC dc(NULL);
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(dc);
+ HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
+
+ T* pT = static_cast<T*>(this);
+ // Create bitmaps for all menu items
+ for(int i = 0; i < nCount; i++)
+ {
+ HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, dc, dcMem);
+ dcMem.SelectBitmap(hBitmapSave);
+ m_arrVistaBitmap.Add(hBitmap);
+ }
+ }
+
+ void _AddVistaBitmapFromImageList(int nIndex)
+ {
+ // Create display compatible memory DC
+ CClientDC dc(NULL);
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(dc);
+ HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
+
+ // Create bitmap for menu item
+ T* pT = static_cast<T*>(this);
+ HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);
+
+ // Select saved bitmap back and add bitmap to the array
+ dcMem.SelectBitmap(hBitmapSave);
+ m_arrVistaBitmap.Add(hBitmap);
+ }
+
+ void _ReplaceVistaBitmapFromImageList(int nIndex)
+ {
+ // Delete existing bitmap
+ if(m_arrVistaBitmap[nIndex] != NULL)
+ ::DeleteObject(m_arrVistaBitmap[nIndex]);
+
+ // Create display compatible memory DC
+ CClientDC dc(NULL);
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(dc);
+ HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
+
+ // Create bitmap for menu item
+ T* pT = static_cast<T*>(this);
+ HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);
+
+ // Select saved bitmap back and replace bitmap in the array
+ dcMem.SelectBitmap(hBitmapSave);
+ m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap);
+ }
+
+ HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget)
+ {
+ // Create 32-bit bitmap
+ BITMAPINFO bi = { 0 };
+ bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bi.bmiHeader.biWidth = m_szBitmap.cx;
+ bi.bmiHeader.biHeight = m_szBitmap.cy;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biSizeImage = 0;
+ bi.bmiHeader.biXPelsPerMeter = 0;
+ bi.bmiHeader.biYPelsPerMeter = 0;
+ bi.bmiHeader.biClrUsed = 0;
+ bi.bmiHeader.biClrImportant = 0;
+ HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0);
+ ATLASSERT(hBitmap != NULL);
+
+ // Select bitmap into target DC and draw from image list to it
+ if(hBitmap != NULL)
+ {
+ ::SelectObject(hDCTarget, hBitmap);
+
+ IMAGELISTDRAWPARAMS ildp = { 0 };
+ ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
+ ildp.himl = m_hImageList;
+ ildp.i = nIndex;
+ ildp.hdcDst = hDCTarget;
+ ildp.x = 0;
+ ildp.y = 0;
+ ildp.cx = 0;
+ ildp.cy = 0;
+ ildp.xBitmap = 0;
+ ildp.yBitmap = 0;
+ ildp.fStyle = ILD_TRANSPARENT;
+ ildp.fState = ILS_ALPHA;
+ ildp.Frame = 255;
+ ::ImageList_DrawIndirect(&ildp);
+ }
+
+ return hBitmap;
+ }
+
+ void _RemoveVistaBitmapsFromMenu()
+ {
+ CMenuHandle menu = m_hMenu;
+ for(int i = 0; i < m_arrCommand.GetSize(); i++)
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_BITMAP;
+ mii.hbmpItem = NULL;
+ menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii);
+ }
+ }
+#endif // _WTL_CMDBAR_VISTA_MENUS
+};
+
+
+class CCommandBarCtrl : public CCommandBarCtrlImpl<CCommandBarCtrl>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName())
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps
+
+template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits>
+{
+public:
+// Data members
+ ATL::CContainedWindow m_wndMDIClient;
+ bool m_bChildMaximized;
+ HWND m_hWndChildMaximized;
+ HICON m_hIconChildMaximized;
+ int m_nBtnPressed;
+ int m_nBtnWasPressed;
+
+ int m_cxyOffset; // offset between nonclient elements
+ int m_cxIconWidth; // small icon width
+ int m_cyIconHeight; // small icon height
+ int m_cxBtnWidth; // nonclient button width
+ int m_cyBtnHeight; // nonclient button height
+ int m_cxLeft; // left nonclient area width
+ int m_cxRight; // right nonclient area width
+
+// Theme declarations and data members
+#ifndef _WTL_NO_AUTO_THEME
+#ifndef _UXTHEME_H_
+ typedef HANDLE HTHEME;
+#endif // !_UXTHEME_H_
+ typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
+ typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme);
+ typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
+ typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc);
+
+ HMODULE m_hThemeDLL;
+ HTHEME m_hTheme;
+ PFN_DrawThemeBackground m_pfnDrawThemeBackground;
+ PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground;
+#endif // !_WTL_NO_AUTO_THEME
+
+// Constructor/destructor
+ CMDICommandBarCtrlImpl() :
+ m_wndMDIClient(this, 2), m_bChildMaximized(false),
+ m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL),
+ m_nBtnPressed(-1), m_nBtnWasPressed(-1),
+#ifndef _WTL_NO_AUTO_THEME
+ m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL),
+#endif // !_WTL_NO_AUTO_THEME
+ m_cxyOffset(2),
+ m_cxIconWidth(16), m_cyIconHeight(16),
+ m_cxBtnWidth(16), m_cyBtnHeight(14),
+ m_cxLeft(20), m_cxRight(55)
+ { }
+
+ ~CMDICommandBarCtrlImpl()
+ {
+ if(m_wndMDIClient.IsWindow())
+/*scary!*/ m_wndMDIClient.UnsubclassWindow();
+ }
+
+// Operations
+ BOOL SetMDIClient(HWND hWndMDIClient)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(::IsWindow(hWndMDIClient));
+ if(!::IsWindow(hWndMDIClient))
+ return FALSE;
+
+#ifdef _DEBUG
+ // BLOCK: Test if the passed window is MDICLIENT
+ {
+ LPCTSTR lpszMDIClientClass = _T("MDICLIENT");
+ const int nNameLen = 9 + 1; // "MDICLIENT" + NULL
+ TCHAR szClassName[nNameLen] = { 0 };
+ ::GetClassName(hWndMDIClient, szClassName, nNameLen);
+ ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0);
+ }
+#endif // _DEBUG
+
+ if(m_wndMDIClient.IsWindow())
+/*scary!*/ m_wndMDIClient.UnsubclassWindow();
+
+ return m_wndMDIClient.SubclassWindow(hWndMDIClient);
+ }
+
+// Message maps
+ typedef CCommandBarCtrlImpl< T, TBase, TWinTraits > _baseClass;
+ BEGIN_MSG_MAP(CMDICommandBarCtrlImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+#ifndef _WTL_NO_AUTO_THEME
+ MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged)
+#endif // !_WTL_NO_AUTO_THEME
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
+ MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
+ MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+ MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
+ MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
+ CHAIN_MSG_MAP(_baseClass)
+ ALT_MSG_MAP(1) // Parent window messages
+ MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)
+ CHAIN_MSG_MAP_ALT(_baseClass, 1)
+ ALT_MSG_MAP(2) // MDI client window messages
+ MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
+ // no chaining needed since this was moved from the base class here
+ ALT_MSG_MAP(3) // Message hook messages
+ MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages)
+ CHAIN_MSG_MAP_ALT(_baseClass, 3)
+ END_MSG_MAP()
+
+// Additional MDI message handlers
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled);
+ if(lRet == (LRESULT)-1)
+ return lRet;
+
+#ifndef _WTL_NO_AUTO_THEME
+ // this will fail if theming is not supported
+ m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
+ if(m_hThemeDLL != NULL)
+ {
+ m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground");
+ ATLASSERT(m_pfnDrawThemeBackground != NULL);
+ if(m_pfnDrawThemeBackground != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_OpenThemeData();
+ }
+ else
+ {
+ ::FreeLibrary(m_hThemeDLL);
+ m_hThemeDLL = NULL;
+ }
+ m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground");
+ ATLASSERT(m_pfnDrawThemeParentBackground != NULL);
+ }
+#endif // !_WTL_NO_AUTO_THEME
+
+ return lRet;
+ }
+
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled);
+
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hThemeDLL != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_CloseThemeData();
+ ::FreeLibrary(m_hThemeDLL);
+ m_hThemeDLL = NULL;
+ }
+#endif // !_WTL_NO_AUTO_THEME
+
+ return lRet;
+ }
+
+#ifndef _WTL_NO_AUTO_THEME
+ LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_hThemeDLL != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_CloseThemeData();
+ pT->_OpenThemeData();
+ }
+ return 0;
+ }
+#endif // !_WTL_NO_AUTO_THEME
+
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ T* pT = static_cast<T*>(this);
+ pT->_AdjustBtnSize(GET_Y_LPARAM(lParam));
+ return lRet;
+ }
+
+ LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+
+ if(m_bChildMaximized && (BOOL)wParam)
+ {
+ LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam;
+ if(m_bLayoutRTL)
+ {
+ lpParams->rgrc[0].left += m_cxRight;
+ lpParams->rgrc[0].right -= m_cxLeft;
+ }
+ else
+ {
+ lpParams->rgrc[0].left += m_cxLeft;
+ lpParams->rgrc[0].right -= m_cxRight;
+ }
+ }
+
+ return lRet;
+ }
+
+ LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+
+ if(!m_bChildMaximized)
+ return lRet;
+
+ ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL);
+
+ // get DC and window rectangle
+ CWindowDC dc(m_hWnd);
+ RECT rect;
+ GetWindowRect(&rect);
+ int cxWidth = rect.right - rect.left;
+ int cyHeight = rect.bottom - rect.top;
+
+ // paint left side nonclient background and draw icon
+ ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight);
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ {
+ if(m_pfnDrawThemeParentBackground != NULL)
+ m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);
+ else
+ dc.FillRect(&rect, COLOR_WINDOW);
+ }
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ {
+ if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)
+ dc.FillRect(&rect, COLOR_3DFACE);
+ else
+ dc.FillRect(&rect, COLOR_MENU);
+ }
+
+ RECT rcIcon = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcIconRect(cxWidth, cyHeight, rcIcon);
+ dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight);
+
+ // paint right side nonclient background
+ ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight);
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ {
+ if(m_pfnDrawThemeParentBackground != NULL)
+ {
+ // this is to account for the left non-client area
+ POINT ptOrg = { 0, 0 };
+ dc.GetViewportOrg(&ptOrg);
+ dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y);
+ ::OffsetRect(&rect, -m_cxLeft, 0);
+
+ m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);
+
+ // restore
+ dc.SetViewportOrg(ptOrg);
+ ::OffsetRect(&rect, m_cxLeft, 0);
+ }
+ else
+ {
+ dc.FillRect(&rect, COLOR_3DFACE);
+ }
+ }
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ {
+ if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)
+ dc.FillRect(&rect, COLOR_3DFACE);
+ else
+ dc.FillRect(&rect, COLOR_MENU);
+ }
+
+ // draw buttons
+ RECT arrRect[3] = { 0 };
+ pT->_CalcBtnRects(cxWidth, cyHeight, arrRect);
+ pT->_DrawMDIButton(dc, arrRect, -1); // draw all buttons
+
+ return lRet;
+ }
+
+ LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(m_bChildMaximized)
+ {
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top };
+ if(m_bLayoutRTL)
+ {
+ if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft)))
+ lRet = HTBORDER;
+ }
+ else
+ {
+ if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight)))
+ lRet = HTBORDER;
+ }
+ }
+ return lRet;
+ }
+
+ LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bChildMaximized)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ ATLASSERT(_DebugCheckChild());
+
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ pt.x -= rect.left;
+ pt.y -= rect.top;
+
+ RECT rcIcon = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);
+ RECT arrRect[3] = { 0 };
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
+
+ if(::PtInRect(&rcIcon, pt))
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n"));
+#endif
+#ifndef TPM_VERPOSANIMATION
+ const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag
+#endif
+ CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);
+ UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |
+ (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized);
+
+ // eat next message if click is on the same button
+ ::OffsetRect(&rcIcon, rect.left, rect.top);
+ MSG msg = { 0 };
+ if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt))
+ ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE);
+
+ if(uRet != 0)
+ ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L);
+ }
+ else if(::PtInRect(&arrRect[0], pt))
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n"));
+#endif
+ m_nBtnWasPressed = m_nBtnPressed = 0;
+ }
+ else if(::PtInRect(&arrRect[1], pt))
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n"));
+#endif
+ m_nBtnWasPressed = m_nBtnPressed = 1;
+ }
+ else if(::PtInRect(&arrRect[2], pt))
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n"));
+#endif
+ m_nBtnWasPressed = m_nBtnPressed = 2;
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+
+ // draw the button state if it was pressed
+ if(m_nBtnPressed != -1)
+ {
+ SetCapture();
+ CWindowDC dc(m_hWnd);
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
+ pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ ClientToScreen(&pt);
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ pt.x -= rect.left;
+ pt.y -= rect.top;
+ RECT arrRect[3] = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
+ int nOldBtnPressed = m_nBtnPressed;
+ m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1;
+ if(nOldBtnPressed != m_nBtnPressed)
+ {
+ CWindowDC dc(m_hWnd);
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
+ pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ ATLASSERT(_DebugCheckChild());
+
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ ClientToScreen(&pt);
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ pt.x -= rect.left;
+ pt.y -= rect.top;
+
+ int nBtn = m_nBtnWasPressed;
+ ReleaseCapture();
+
+ RECT arrRect[3] = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
+ if(::PtInRect(&arrRect[nBtn], pt))
+ {
+ switch(nBtn)
+ {
+ case 0: // close
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n"));
+#endif
+ ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+ case 1: // restore
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n"));
+#endif
+ ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L);
+ break;
+ case 2: // minimize
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n"));
+#endif
+ ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bChildMaximized || m_nBtnWasPressed != -1)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ ATLASSERT(_DebugCheckChild());
+
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ pt.x -= rect.left;
+ pt.y -= rect.top;
+
+ RECT rcIcon = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);
+ RECT arrRect[3] = { 0 };
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
+
+ if(::PtInRect(&rcIcon, pt))
+ {
+ CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);
+ UINT uDefID = menu.GetMenuDefaultItem();
+ if(uDefID == (UINT)-1)
+ uDefID = SC_CLOSE;
+ ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_bChildMaximized)
+ {
+ if(m_nBtnPressed != -1)
+ {
+ ATLASSERT(m_nBtnPressed == m_nBtnWasPressed); // must be
+ m_nBtnPressed = -1;
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ RECT arrRect[3] = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
+ CWindowDC dc(m_hWnd);
+ pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed);
+ }
+ m_nBtnWasPressed = -1;
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+ return 0;
+ }
+
+// Parent window message handlers
+ LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);
+ RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);
+ bHandled = FALSE;
+ return 1;
+ }
+
+// MDI client window message handlers
+ LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam);
+ HMENU hOldMenu = GetMenu();
+ BOOL bRet = AttachMenu((HMENU)wParam);
+ bRet; // avoid level 4 warning
+ ATLASSERT(bRet);
+
+#if (_WIN32_IE >= 0x0400)
+ T* pT = static_cast<T*>(this);
+ pT->UpdateRebarBandIdealSize();
+#endif // (_WIN32_IE >= 0x0400)
+
+ return (LRESULT)hOldMenu;
+ }
+
+// All messages from the message hook
+ LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_ProcessAllHookMessages(uMsg, wParam, lParam);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+// Overrideables
+ // override this to provide different ideal size
+ void UpdateRebarBandIdealSize()
+ {
+ // assuming we are in a rebar, change ideal size to our size
+ // we hope that if we are not in a rebar, nCount will be 0
+ int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);
+ for(int i = 0; i < nCount; i++)
+ {
+ REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };
+ ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
+ if(rbi.hwndChild == m_hWnd)
+ {
+ rbi.fMask = RBBIM_IDEALSIZE;
+ rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0;
+ int nBtnCount = GetButtonCount();
+ if(nBtnCount > 0)
+ {
+ RECT rect = { 0 };
+ GetItemRect(nBtnCount - 1, &rect);
+ rbi.cxIdeal += rect.right;
+ }
+ ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
+ break;
+ }
+ }
+ }
+
+ // all hook messages - check for the maximized MDI child window change
+ void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
+ {
+ if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU)
+ return;
+
+ BOOL bMaximized = FALSE;
+ HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
+ bool bMaxOld = m_bChildMaximized;
+ m_bChildMaximized = (hWndChild != NULL && bMaximized);
+ HICON hIconOld = m_hIconChildMaximized;
+
+ if(m_bChildMaximized)
+ {
+ if(m_hWndChildMaximized != hWndChild)
+ {
+ ATL::CWindow wnd = m_hWndChildMaximized = hWndChild;
+ m_hIconChildMaximized = wnd.GetIcon(FALSE);
+ if(m_hIconChildMaximized == NULL)
+ {
+ m_hIconChildMaximized = wnd.GetIcon(TRUE);
+ if(m_hIconChildMaximized == NULL)
+ {
+ // no icon set with WM_SETICON, get the class one
+// need conditional code because types don't match in winuser.h
+#ifdef _WIN64
+ m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM);
+#else
+ m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM));
+#endif
+ }
+ }
+ }
+ }
+ else
+ {
+ m_hWndChildMaximized = NULL;
+ m_hIconChildMaximized = NULL;
+ }
+
+ if(bMaxOld != m_bChildMaximized)
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false");
+#endif
+ // assuming we are in a rebar, change our size to accomodate new state
+ // we hope that if we are not in a rebar, nCount will be 0
+ int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);
+ int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight);
+ for(int i = 0; i < nCount; i++)
+ {
+#if (_WIN32_IE >= 0x0500)
+ REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };
+ ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
+ if(rbi.hwndChild == m_hWnd)
+ {
+ if((rbi.fStyle & RBBS_USECHEVRON) != 0)
+ {
+ rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
+ rbi.cxMinChild += cxDiff;
+ rbi.cxIdeal += cxDiff;
+ ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
+ }
+ break;
+ }
+#elif (_WIN32_IE >= 0x0400)
+ REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };
+ ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
+ if(rbi.hwndChild == m_hWnd)
+ {
+ rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
+ rbi.cxMinChild += cxDiff;
+ rbi.cxIdeal += cxDiff;
+ ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
+ break;
+ }
+#else // (_WIN32_IE < 0x0400)
+ REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE };
+ ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
+ if(rbi.hwndChild == m_hWnd)
+ {
+ rbi.fMask = RBBIM_CHILDSIZE;
+ rbi.cxMinChild += cxDiff;
+ ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
+ break;
+ }
+#endif // (_WIN32_IE < 0x0400)
+ }
+ }
+
+ if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized)
+ {
+ // force size change and redraw everything
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2);
+ SetRedraw(FALSE);
+ SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE);
+ SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);
+ SetRedraw(TRUE);
+ RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+ }
+
+// Implementation
+ void GetSystemSettings()
+ {
+#ifdef _CMDBAR_EXTRA_TRACE
+ ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n"));
+#endif
+ _baseClass::GetSystemSettings();
+
+ NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
+ ATLASSERT(bRet);
+ if(bRet)
+ {
+ m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON);
+ m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON);
+ m_cxLeft = m_cxIconWidth;
+
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ {
+ m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset;
+ m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;
+ m_cxRight = 3 * m_cxBtnWidth;
+ }
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ {
+ m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset;
+ m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;
+ m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;
+ }
+ }
+
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+ T* pT = static_cast<T*>(this);
+ pT->_AdjustBtnSize(rect.bottom);
+ }
+
+ void _AdjustBtnSize(int cyHeight)
+ {
+ if(cyHeight > 1 && m_cyBtnHeight > cyHeight)
+ {
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ {
+ m_cyBtnHeight = cyHeight;
+ m_cxBtnWidth = cyHeight;
+ m_cxRight = 3 * m_cxBtnWidth;
+ }
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ {
+ m_cyBtnHeight = cyHeight;
+ m_cxBtnWidth = cyHeight + m_cxyOffset;
+ m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;
+ }
+ }
+ }
+
+ void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const
+ {
+ int xStart = (m_cxLeft - m_cxIconWidth) / 2;
+ if(xStart < 0)
+ xStart = 0;
+ int yStart = (cyHeight - m_cyIconHeight) / 2;
+ if(yStart < 0)
+ yStart = 0;
+
+ if(bInvertX)
+ ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight);
+ else
+ ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight);
+ }
+
+ void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const
+ {
+ int yStart = (cyHeight - m_cyBtnHeight) / 2;
+ if(yStart < 0)
+ yStart = 0;
+
+ RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight };
+ int nDirection = -1;
+ if(bInvertX)
+ {
+ ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight);
+ nDirection = 1;
+ }
+
+ arrRect[0] = rcBtn;
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0);
+ arrRect[1] = rcBtn;
+ ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);
+ arrRect[2] = rcBtn;
+ }
+
+ void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn)
+ {
+#ifndef _WTL_NO_AUTO_THEME
+ if(m_hTheme != NULL)
+ {
+#ifndef TMSCHEMA_H
+ const int WP_MDICLOSEBUTTON = 20;
+ const int CBS_NORMAL = 1;
+ const int CBS_PUSHED = 3;
+ const int CBS_DISABLED = 4;
+ const int WP_MDIRESTOREBUTTON = 22;
+ const int RBS_NORMAL = 1;
+ const int RBS_PUSHED = 3;
+ const int RBS_DISABLED = 4;
+ const int WP_MDIMINBUTTON = 16;
+ const int MINBS_NORMAL = 1;
+ const int MINBS_PUSHED = 3;
+ const int MINBS_DISABLED = 4;
+#endif // TMSCHEMA_H
+ if(nBtn == -1 || nBtn == 0)
+ m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL);
+ if(nBtn == -1 || nBtn == 1)
+ m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL);
+ if(nBtn == -1 || nBtn == 2)
+ m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL);
+ }
+ else
+#endif // !_WTL_NO_AUTO_THEME
+ {
+ if(nBtn == -1 || nBtn == 0)
+ dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0));
+ if(nBtn == -1 || nBtn == 1)
+ dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0));
+ if(nBtn == -1 || nBtn == 2)
+ dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0));
+ }
+ }
+
+#ifndef _WTL_NO_AUTO_THEME
+ static UINT _GetThemeChangedMsg()
+ {
+#ifndef WM_THEMECHANGED
+ static const UINT WM_THEMECHANGED = 0x031A;
+#endif // !WM_THEMECHANGED
+ return WM_THEMECHANGED;
+ }
+
+ void _OpenThemeData()
+ {
+ ATLASSERT(m_hThemeDLL != NULL);
+
+ PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData");
+ ATLASSERT(pfnOpenThemeData != NULL);
+ if(pfnOpenThemeData != NULL)
+ m_hTheme = pfnOpenThemeData(m_hWnd, L"Window");
+ }
+
+ void _CloseThemeData()
+ {
+ ATLASSERT(m_hThemeDLL != NULL);
+
+ if(m_hTheme == NULL)
+ return; // nothing to do
+
+ PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData");
+ ATLASSERT(pfnCloseThemeData != NULL);
+ if(pfnCloseThemeData != NULL)
+ {
+ pfnCloseThemeData(m_hTheme);
+ m_hTheme = NULL;
+ }
+ }
+#endif // !_WTL_NO_AUTO_THEME
+
+ bool _DebugCheckChild()
+ {
+#ifdef _DEBUG
+ BOOL bMaximized = FALSE;
+ HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
+ return (bMaximized && hWndChild == m_hWndChildMaximized);
+#else // !_DEBUG
+ return true;
+#endif // !_DEBUG
+ }
+};
+
+class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl<CMDICommandBarCtrl>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName())
+};
+
+}; // namespace WTL
+
+#endif // __ATLCTRLW_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLCTRLX_H__
+#define __ATLCTRLX_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlctrlx.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLCTRLS_H__
+ #error atlctrlx.h requires atlctrls.h to be included first
+#endif
+
+#ifndef WM_UPDATEUISTATE
+ #define WM_UPDATEUISTATE 0x0128
+#endif // !WM_UPDATEUISTATE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CBitmapButtonImpl<T, TBase, TWinTraits>
+// CBitmapButton
+// CCheckListViewCtrlImpl<T, TBase, TWinTraits>
+// CCheckListViewCtrl
+// CHyperLinkImpl<T, TBase, TWinTraits>
+// CHyperLink
+// CWaitCursor
+// CCustomWaitCursor
+// CMultiPaneStatusBarCtrlImpl<T, TBase>
+// CMultiPaneStatusBarCtrl
+// CPaneContainerImpl<T, TBase, TWinTraits>
+// CPaneContainer
+// CSortListViewImpl<T>
+// CSortListViewCtrlImpl<T, TBase, TWinTraits>
+// CSortListViewCtrl
+// CTabViewImpl<T, TBase, TWinTraits>
+// CTabView
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CBitmapButton - bitmap button implementation
+
+#ifndef _WIN32_WCE
+
+// bitmap button extended styles
+#define BMPBTN_HOVER 0x00000001
+#define BMPBTN_AUTO3D_SINGLE 0x00000002
+#define BMPBTN_AUTO3D_DOUBLE 0x00000004
+#define BMPBTN_AUTOSIZE 0x00000008
+#define BMPBTN_SHAREIMAGELISTS 0x00000010
+#define BMPBTN_AUTOFIRE 0x00000020
+
+template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits>
+{
+public:
+ DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
+
+ enum
+ {
+ _nImageNormal = 0,
+ _nImagePushed,
+ _nImageFocusOrHover,
+ _nImageDisabled,
+
+ _nImageCount = 4,
+ };
+
+ enum
+ {
+ ID_TIMER_FIRST = 1000,
+ ID_TIMER_REPEAT = 1001
+ };
+
+ // Bitmap button specific extended styles
+ DWORD m_dwExtendedStyle;
+
+ CImageList m_ImageList;
+ int m_nImage[_nImageCount];
+
+ CToolTipCtrl m_tip;
+ LPTSTR m_lpstrToolTipText;
+
+ // Internal states
+ unsigned m_fMouseOver:1;
+ unsigned m_fFocus:1;
+ unsigned m_fPressed:1;
+
+
+// Constructor/Destructor
+ CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
+ m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedStyle),
+ m_lpstrToolTipText(NULL),
+ m_fMouseOver(0), m_fFocus(0), m_fPressed(0)
+ {
+ m_nImage[_nImageNormal] = -1;
+ m_nImage[_nImagePushed] = -1;
+ m_nImage[_nImageFocusOrHover] = -1;
+ m_nImage[_nImageDisabled] = -1;
+ }
+
+ ~CBitmapButtonImpl()
+ {
+ if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)
+ m_ImageList.Destroy();
+ delete [] m_lpstrToolTipText;
+ }
+
+ // overridden to provide proper initialization
+ BOOL SubclassWindow(HWND hWnd)
+ {
+#if (_MSC_VER >= 1300)
+ BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
+ BOOL bRet = _baseClass::SubclassWindow(hWnd);
+#endif // !(_MSC_VER >= 1300)
+ if(bRet)
+ Init();
+ return bRet;
+ }
+
+// Attributes
+ DWORD GetBitmapButtonExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ return dwPrevStyle;
+ }
+
+ HIMAGELIST GetImageList() const
+ {
+ return m_ImageList;
+ }
+
+ HIMAGELIST SetImageList(HIMAGELIST hImageList)
+ {
+ HIMAGELIST hImageListPrev = m_ImageList;
+ m_ImageList = hImageList;
+ if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd))
+ SizeToImage();
+ return hImageListPrev;
+ }
+
+ int GetToolTipTextLength() const
+ {
+ return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText);
+ }
+
+ bool GetToolTipText(LPTSTR lpstrText, int nLength) const
+ {
+ ATLASSERT(lpstrText != NULL);
+ if(m_lpstrToolTipText == NULL)
+ return false;
+
+ errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE);
+
+ return (nRet == 0 || nRet == STRUNCATE);
+ }
+
+ bool SetToolTipText(LPCTSTR lpstrText)
+ {
+ if(m_lpstrToolTipText != NULL)
+ {
+ delete [] m_lpstrToolTipText;
+ m_lpstrToolTipText = NULL;
+ }
+
+ if(lpstrText == NULL)
+ {
+ if(m_tip.IsWindow())
+ m_tip.Activate(FALSE);
+ return true;
+ }
+
+ int cchLen = lstrlen(lpstrText) + 1;
+ ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]);
+ if(m_lpstrToolTipText == NULL)
+ return false;
+
+ SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText);
+ if(m_tip.IsWindow())
+ {
+ m_tip.Activate(TRUE);
+ m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
+ }
+
+ return true;
+ }
+
+// Operations
+ void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1)
+ {
+ if(nNormal != -1)
+ m_nImage[_nImageNormal] = nNormal;
+ if(nPushed != -1)
+ m_nImage[_nImagePushed] = nPushed;
+ if(nFocusOrHover != -1)
+ m_nImage[_nImageFocusOrHover] = nFocusOrHover;
+ if(nDisabled != -1)
+ m_nImage[_nImageDisabled] = nDisabled;
+ }
+
+ BOOL SizeToImage()
+ {
+ ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL);
+ int cx = 0;
+ int cy = 0;
+ if(!m_ImageList.GetIconSize(cx, cy))
+ return FALSE;
+ return ResizeClient(cx, cy);
+ }
+
+// Overrideables
+ void DoPaint(CDCHandle dc)
+ {
+ ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set
+ ATLASSERT(m_nImage[0] != -1); // main bitmap must be set
+
+ // set bitmap according to the current button state
+ int nImage = -1;
+ bool bHover = IsHoverMode();
+ if(!IsWindowEnabled())
+ nImage = m_nImage[_nImageDisabled];
+ else if(m_fPressed == 1)
+ nImage = m_nImage[_nImagePushed];
+ else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1))
+ nImage = m_nImage[_nImageFocusOrHover];
+ if(nImage == -1) // not there, use default one
+ nImage = m_nImage[_nImageNormal];
+
+ // draw the button image
+ int xyPos = 0;
+ if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1))
+ xyPos = 1;
+ m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);
+
+ // draw 3D border if required
+ if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0)
+ {
+ RECT rect;
+ GetClientRect(&rect);
+
+ if(m_fPressed == 1)
+ dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);
+ else if(!bHover || m_fMouseOver == 1)
+ dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);
+
+ if(!bHover && m_fFocus == 1)
+ {
+ ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
+ dc.DrawFocusRect(&rect);
+ }
+ }
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CBitmapButtonImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
+ MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+ MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
+ MESSAGE_HANDLER(WM_ENABLE, OnEnable)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+ MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
+ MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
+ MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
+ MESSAGE_HANDLER(WM_TIMER, OnTimer)
+ MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ Init();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_tip.IsWindow())
+ {
+ m_tip.DestroyWindow();
+ m_tip.m_hWnd = NULL;
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ MSG msg = { m_hWnd, uMsg, wParam, lParam };
+ if(m_tip.IsWindow())
+ m_tip.RelayEvent(&msg);
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background needed
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ if(wParam != NULL)
+ {
+ pT->DoPaint((HDC)wParam);
+ }
+ else
+ {
+ CPaintDC dc(m_hWnd);
+ pT->DoPaint(dc.m_hDC);
+ }
+ return 0;
+ }
+
+ LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;
+ Invalidate();
+ UpdateWindow();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = 0;
+ if(IsHoverMode())
+ SetCapture();
+ else
+ lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(::GetCapture() == m_hWnd)
+ {
+ m_fPressed = 1;
+ Invalidate();
+ UpdateWindow();
+ }
+ if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0)
+ {
+ int nElapse = 250;
+ int nDelay = 0;
+ if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))
+ nElapse += nDelay * 250; // all milli-seconds
+ SetTimer(ID_TIMER_FIRST, nElapse);
+ }
+ return lRet;
+ }
+
+ LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = 0;
+ if(!IsHoverMode())
+ lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(::GetCapture() != m_hWnd)
+ SetCapture();
+ if(m_fPressed == 0)
+ {
+ m_fPressed = 1;
+ Invalidate();
+ UpdateWindow();
+ }
+ return lRet;
+ }
+
+ LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = 0;
+ bool bHover = IsHoverMode();
+ if(!bHover)
+ lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(::GetCapture() == m_hWnd)
+ {
+ if(bHover && m_fPressed == 1)
+ ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
+ ::ReleaseCapture();
+ }
+ return lRet;
+ }
+
+ LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_fPressed == 1)
+ {
+ m_fPressed = 0;
+ Invalidate();
+ UpdateWindow();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ Invalidate();
+ UpdateWindow();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(::GetCapture() == m_hWnd)
+ {
+ POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ ClientToScreen(&ptCursor);
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;
+ if(m_fPressed != uPressed)
+ {
+ m_fPressed = uPressed;
+ Invalidate();
+ UpdateWindow();
+ }
+ }
+ else if(IsHoverMode() && m_fMouseOver == 0)
+ {
+ m_fMouseOver = 1;
+ Invalidate();
+ UpdateWindow();
+ StartTrackMouseLeave();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_fMouseOver == 1)
+ {
+ m_fMouseOver = 0;
+ Invalidate();
+ UpdateWindow();
+ }
+ return 0;
+ }
+
+ LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam == VK_SPACE && IsHoverMode())
+ return 0; // ignore if in hover mode
+ if(wParam == VK_SPACE && m_fPressed == 0)
+ {
+ m_fPressed = 1;
+ Invalidate();
+ UpdateWindow();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam == VK_SPACE && IsHoverMode())
+ return 0; // ignore if in hover mode
+ if(wParam == VK_SPACE && m_fPressed == 1)
+ {
+ m_fPressed = 0;
+ Invalidate();
+ UpdateWindow();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);
+ switch(wParam) // timer ID
+ {
+ case ID_TIMER_FIRST:
+ KillTimer(ID_TIMER_FIRST);
+ if(m_fPressed == 1)
+ {
+ ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
+ int nElapse = 250;
+ int nRepeat = 40;
+ if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
+ nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated
+ SetTimer(ID_TIMER_REPEAT, nElapse);
+ }
+ break;
+ case ID_TIMER_REPEAT:
+ if(m_fPressed == 1)
+ ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
+ else if(::GetCapture() != m_hWnd)
+ KillTimer(ID_TIMER_REPEAT);
+ break;
+ default: // not our timer
+ break;
+ }
+ return 0;
+ }
+
+ LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ // If the control is subclassed or superclassed, this message can cause
+ // repainting without WM_PAINT. We don't use this state, so just do nothing.
+ return 0;
+ }
+
+// Implementation
+ void Init()
+ {
+ // We need this style to prevent Windows from painting the button
+ ModifyStyle(0, BS_OWNERDRAW);
+
+ // create a tool tip
+ m_tip.Create(m_hWnd);
+ ATLASSERT(m_tip.IsWindow());
+ if(m_tip.IsWindow() && m_lpstrToolTipText != NULL)
+ {
+ m_tip.Activate(TRUE);
+ m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
+ }
+
+ if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0)
+ SizeToImage();
+ }
+
+ BOOL StartTrackMouseLeave()
+ {
+ TRACKMOUSEEVENT tme = { 0 };
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = m_hWnd;
+ return _TrackMouseEvent(&tme);
+ }
+
+ bool IsHoverMode() const
+ {
+ return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);
+ }
+};
+
+class CBitmapButton : public CBitmapButtonImpl<CBitmapButton>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
+
+ CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
+ CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)
+ { }
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCheckListCtrlView - list view control with check boxes
+
+template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>
+class CCheckListViewCtrlImplTraits
+{
+public:
+ static DWORD GetWndStyle(DWORD dwStyle)
+ {
+ return (dwStyle == 0) ? t_dwStyle : dwStyle;
+ }
+
+ static DWORD GetWndExStyle(DWORD dwExStyle)
+ {
+ return (dwExStyle == 0) ? t_dwExStyle : dwExStyle;
+ }
+
+ static DWORD GetExtendedLVStyle()
+ {
+ return t_dwExListViewStyle;
+ }
+};
+
+typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CCheckListViewCtrlTraits;
+
+template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits>
+class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>
+{
+public:
+ DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
+
+// Attributes
+ static DWORD GetExtendedLVStyle()
+ {
+ return TWinTraits::GetExtendedLVStyle();
+ }
+
+// Operations
+ BOOL SubclassWindow(HWND hWnd)
+ {
+#if (_MSC_VER >= 1300)
+ BOOL bRet = ATL::CWindowImplBaseT< TBase, TWinTraits>::SubclassWindow(hWnd);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImplBaseT< TBase, TWinTraits> _baseClass;
+ BOOL bRet = _baseClass::SubclassWindow(hWnd);
+#endif // !(_MSC_VER >= 1300)
+ if(bRet)
+ {
+ T* pT = static_cast<T*>(this);
+ pT;
+ ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
+ SetExtendedListViewStyle(pT->GetExtendedLVStyle());
+ }
+ return bRet;
+ }
+
+ void CheckSelectedItems(int nCurrItem)
+ {
+ // first check if this item is selected
+ LVITEM lvi = { 0 };
+ lvi.iItem = nCurrItem;
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_STATE;
+ lvi.stateMask = LVIS_SELECTED;
+ GetItem(&lvi);
+ // if item is not selected, don't do anything
+ if(!(lvi.state & LVIS_SELECTED))
+ return;
+ // new check state will be reverse of the current state,
+ BOOL bCheck = !GetCheckState(nCurrItem);
+ int nItem = -1;
+ int nOldItem = -1;
+ while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1)
+ {
+ if(nItem != nCurrItem)
+ SetCheckState(nItem, bCheck);
+ nOldItem = nItem;
+ }
+ }
+
+// Implementation
+ BEGIN_MSG_MAP(CCheckListViewCtrlImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+ MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
+ MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ // first let list view control initialize everything
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ T* pT = static_cast<T*>(this);
+ pT;
+ ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
+ SetExtendedListViewStyle(pT->GetExtendedLVStyle());
+ return lRet;
+ }
+
+ LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ LVHITTESTINFO lvh = { 0 };
+ lvh.pt = ptMsg;
+ if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CheckSelectedItems(lvh.iItem);
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam == VK_SPACE)
+ {
+ int nCurrItem = GetNextItem(-1, LVNI_FOCUSED);
+ if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CheckSelectedItems(nCurrItem);
+ }
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+};
+
+class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CHyperLink - hyper link control implementation
+
+#if (WINVER < 0x0500) && !defined(_WIN32_WCE)
+__declspec(selectany) struct
+{
+ enum { cxWidth = 32, cyHeight = 32 };
+ int xHotSpot;
+ int yHotSpot;
+ unsigned char arrANDPlane[cxWidth * cyHeight / 8];
+ unsigned char arrXORPlane[cxWidth * cyHeight / 8];
+} _AtlHyperLink_CursorData =
+{
+ 5, 0,
+ {
+ 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
+ 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF,
+ 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
+ 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
+ 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ },
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00,
+ 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00,
+ 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00,
+ 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
+ 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ }
+};
+#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
+
+#define HLINK_UNDERLINED 0x00000000
+#define HLINK_NOTUNDERLINED 0x00000001
+#define HLINK_UNDERLINEHOVER 0x00000002
+#define HLINK_COMMANDBUTTON 0x00000004
+#define HLINK_NOTIFYBUTTON 0x0000000C
+#define HLINK_USETAGS 0x00000010
+#define HLINK_USETAGSBOLD 0x00000030
+#define HLINK_NOTOOLTIP 0x00000040
+#define HLINK_AUTOCREATELINKFONT 0x00000080
+#define HLINK_SINGLELINE 0x00000100
+
+// Notes:
+// - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
+// - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
+{
+public:
+ LPTSTR m_lpstrLabel;
+ LPTSTR m_lpstrHyperLink;
+
+ HCURSOR m_hCursor;
+ HFONT m_hFontLink;
+ HFONT m_hFontNormal;
+
+ RECT m_rcLink;
+#ifndef _WIN32_WCE
+ CToolTipCtrl m_tip;
+#endif // !_WIN32_WCE
+
+ COLORREF m_clrLink;
+ COLORREF m_clrVisited;
+
+ DWORD m_dwExtendedStyle; // Hyper Link specific extended styles
+
+ bool m_bPaintLabel:1;
+ bool m_bVisited:1;
+ bool m_bHover:1;
+ bool m_bInternalLinkFont:1;
+ bool m_bInternalNormalFont:1;
+
+
+// Constructor/Destructor
+ CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) :
+ m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),
+ m_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL),
+ m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),
+ m_dwExtendedStyle(dwExtendedStyle),
+ m_bPaintLabel(true), m_bVisited(false),
+ m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false)
+ {
+ ::SetRectEmpty(&m_rcLink);
+ }
+
+ ~CHyperLinkImpl()
+ {
+ delete [] m_lpstrLabel;
+ delete [] m_lpstrHyperLink;
+#if (WINVER < 0x0500) && !defined(_WIN32_WCE)
+ // It was created, not loaded, so we have to destroy it
+ if(m_hCursor != NULL)
+ ::DestroyCursor(m_hCursor);
+#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
+ }
+
+// Attributes
+ DWORD GetHyperLinkExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ return dwPrevStyle;
+ }
+
+ bool GetLabel(LPTSTR lpstrBuffer, int nLength) const
+ {
+ if(m_lpstrLabel == NULL)
+ return false;
+ ATLASSERT(lpstrBuffer != NULL);
+ if(nLength <= lstrlen(m_lpstrLabel))
+ return false;
+
+ SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel);
+
+ return true;
+ }
+
+ bool SetLabel(LPCTSTR lpstrLabel)
+ {
+ delete [] m_lpstrLabel;
+ m_lpstrLabel = NULL;
+ int cchLen = lstrlen(lpstrLabel) + 1;
+ ATLTRY(m_lpstrLabel = new TCHAR[cchLen]);
+ if(m_lpstrLabel == NULL)
+ return false;
+
+ SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel);
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+
+ if(m_hWnd != NULL)
+ SetWindowText(lpstrLabel); // Set this for accessibility
+
+ return true;
+ }
+
+ bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const
+ {
+ if(m_lpstrHyperLink == NULL)
+ return false;
+ ATLASSERT(lpstrBuffer != NULL);
+ if(nLength <= lstrlen(m_lpstrHyperLink))
+ return false;
+
+ SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink);
+
+ return true;
+ }
+
+ bool SetHyperLink(LPCTSTR lpstrLink)
+ {
+ delete [] m_lpstrHyperLink;
+ m_lpstrHyperLink = NULL;
+ int cchLen = lstrlen(lpstrLink) + 1;
+ ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]);
+ if(m_lpstrHyperLink == NULL)
+ return false;
+
+ SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink);
+ if(m_lpstrLabel == NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+ }
+#ifndef _WIN32_WCE
+ if(m_tip.IsWindow())
+ {
+ m_tip.Activate(TRUE);
+ m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
+ }
+#endif // !_WIN32_WCE
+ return true;
+ }
+
+ HFONT GetLinkFont() const
+ {
+ return m_hFontLink;
+ }
+
+ void SetLinkFont(HFONT hFont)
+ {
+ if(m_bInternalLinkFont)
+ {
+ ::DeleteObject(m_hFontLink);
+ m_bInternalLinkFont = false;
+ }
+
+ m_hFontLink = hFont;
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+ }
+
+ int GetIdealHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
+ return -1;
+ if(!m_bPaintLabel)
+ return -1;
+
+ UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+
+ CClientDC dc(m_hWnd);
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+ HFONT hFontOld = dc.SelectFont(m_hFontNormal);
+ RECT rcText = rect;
+ dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT);
+ dc.SelectFont(m_hFontLink);
+ RECT rcLink = rect;
+ dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
+ dc.SelectFont(hFontOld);
+ return max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top);
+ }
+
+ bool GetIdealSize(SIZE& size) const
+ {
+ int cx = 0, cy = 0;
+ bool bRet = GetIdealSize(cx, cy);
+ if(bRet)
+ {
+ size.cx = cx;
+ size.cy = cy;
+ }
+ return bRet;
+ }
+
+ bool GetIdealSize(int& cx, int& cy) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
+ return false;
+ if(!m_bPaintLabel)
+ return false;
+
+ CClientDC dc(m_hWnd);
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ RECT rcAll = rcClient;
+
+ if(IsUsingTags())
+ {
+ // find tags and label parts
+ LPTSTR lpstrLeft = NULL;
+ int cchLeft = 0;
+ LPTSTR lpstrLink = NULL;
+ int cchLink = 0;
+ LPTSTR lpstrRight = NULL;
+ int cchRight = 0;
+
+ const T* pT = static_cast<const T*>(this);
+ pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
+
+ // get label part rects
+ UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+
+ HFONT hFontOld = dc.SelectFont(m_hFontNormal);
+ RECT rcLeft = rcClient;
+ dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
+
+ dc.SelectFont(m_hFontLink);
+ RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom };
+ dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
+
+ dc.SelectFont(m_hFontNormal);
+ RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom };
+ dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT);
+
+ dc.SelectFont(hFontOld);
+
+ int cyMax = max(rcLeft.bottom, max(rcLink.bottom, rcRight.bottom));
+ ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax);
+ }
+ else
+ {
+ HFONT hOldFont = NULL;
+ if(m_hFontLink != NULL)
+ hOldFont = dc.SelectFont(m_hFontLink);
+ LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
+ DWORD dwStyle = GetStyle();
+ UINT uFormat = DT_LEFT;
+ if (dwStyle & SS_CENTER)
+ uFormat = DT_CENTER;
+ else if (dwStyle & SS_RIGHT)
+ uFormat = DT_RIGHT;
+ uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+ dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT);
+ if(m_hFontLink != NULL)
+ dc.SelectFont(hOldFont);
+ if (dwStyle & SS_CENTER)
+ {
+ int dx = (rcClient.right - rcAll.right) / 2;
+ ::OffsetRect(&rcAll, dx, 0);
+ }
+ else if (dwStyle & SS_RIGHT)
+ {
+ int dx = rcClient.right - rcAll.right;
+ ::OffsetRect(&rcAll, dx, 0);
+ }
+ }
+
+ cx = rcAll.right - rcAll.left;
+ cy = rcAll.bottom - rcAll.top;
+
+ return true;
+ }
+
+ // for command buttons only
+ bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const
+ {
+ ATLASSERT(IsCommandButton());
+ return GetHyperLink(lpstrBuffer, nLength);
+ }
+
+ bool SetToolTipText(LPCTSTR lpstrToolTipText)
+ {
+ ATLASSERT(IsCommandButton());
+ return SetHyperLink(lpstrToolTipText);
+ }
+
+// Operations
+ BOOL SubclassWindow(HWND hWnd)
+ {
+ ATLASSERT(m_hWnd == NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ if(m_hFontNormal == NULL)
+ m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
+#if (_MSC_VER >= 1300)
+ BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
+ BOOL bRet = _baseClass::SubclassWindow(hWnd);
+#endif // !(_MSC_VER >= 1300)
+ if(bRet)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Init();
+ }
+ return bRet;
+ }
+
+ bool Navigate()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ bool bRet = true;
+ if(IsNotifyButton())
+ {
+ NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), NM_CLICK };
+ ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);
+ }
+ else if(IsCommandButton())
+ {
+ ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
+ }
+ else
+ {
+ ATLASSERT(m_lpstrHyperLink != NULL);
+#ifndef _WIN32_WCE
+ DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
+ bRet = (dwRet > 32);
+#else // CE specific
+ SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 };
+ ::ShellExecuteEx(&shExeInfo);
+ DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp;
+ bRet = (dwRet == 0) || (dwRet > 32);
+#endif // _WIN32_WCE
+ ATLASSERT(bRet);
+ if(bRet)
+ {
+ m_bVisited = true;
+ Invalidate();
+ }
+ }
+ return bRet;
+ }
+
+ void CreateLinkFontFromNormal()
+ {
+ if(m_bInternalLinkFont)
+ {
+ ::DeleteObject(m_hFontLink);
+ m_bInternalLinkFont = false;
+ }
+
+ CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT);
+ LOGFONT lf = { 0 };
+ font.GetLogFont(&lf);
+
+ if(IsUsingTagsBold())
+ lf.lfWeight = FW_BOLD;
+ else if(!IsNotUnderlined())
+ lf.lfUnderline = TRUE;
+
+ m_hFontLink = ::CreateFontIndirect(&lf);
+ m_bInternalLinkFont = true;
+ ATLASSERT(m_hFontLink != NULL);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CHyperLinkImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
+ MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
+ MESSAGE_HANDLER(WM_CHAR, OnChar)
+ MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
+ MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
+ MESSAGE_HANDLER(WM_ENABLE, OnEnable)
+ MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
+ MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
+ MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Init();
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_tip.IsWindow())
+ {
+ m_tip.DestroyWindow();
+ m_tip.m_hWnd = NULL;
+ }
+
+ if(m_bInternalLinkFont)
+ {
+ ::DeleteObject(m_hFontLink);
+ m_hFontLink = NULL;
+ m_bInternalLinkFont = false;
+ }
+
+ if(m_bInternalNormalFont)
+ {
+ ::DeleteObject(m_hFontNormal);
+ m_hFontNormal = NULL;
+ m_bInternalNormalFont = false;
+ }
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ MSG msg = { m_hWnd, uMsg, wParam, lParam };
+ if(m_tip.IsWindow() && IsUsingToolTip())
+ m_tip.RelayEvent(&msg);
+ bHandled = FALSE;
+ return 1;
+ }
+#endif // !_WIN32_WCE
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background painting needed (we do it all during WM_PAINT)
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(!m_bPaintLabel)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ T* pT = static_cast<T*>(this);
+ if(wParam != NULL)
+ {
+ pT->DoEraseBackground((HDC)wParam);
+ pT->DoPaint((HDC)wParam);
+ }
+ else
+ {
+ CPaintDC dc(m_hWnd);
+ pT->DoEraseBackground(dc.m_hDC);
+ pT->DoPaint(dc.m_hDC);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_bPaintLabel)
+ Invalidate();
+ else
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
+ {
+ ::SetCursor(m_hCursor);
+ if(IsUnderlineHover())
+ {
+ if(!m_bHover)
+ {
+ m_bHover = true;
+ InvalidateRect(&m_rcLink);
+ UpdateWindow();
+#ifndef _WIN32_WCE
+ StartTrackMouseLeave();
+#endif // !_WIN32_WCE
+ }
+ }
+ }
+ else
+ {
+ if(IsUnderlineHover())
+ {
+ if(m_bHover)
+ {
+ m_bHover = false;
+ InvalidateRect(&m_rcLink);
+ UpdateWindow();
+ }
+ }
+ bHandled = FALSE;
+ }
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(IsUnderlineHover() && m_bHover)
+ {
+ m_bHover = false;
+ InvalidateRect(&m_rcLink);
+ UpdateWindow();
+ }
+ return 0;
+ }
+#endif // !_WIN32_WCE
+
+ LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ if(::PtInRect(&m_rcLink, pt))
+ {
+ SetFocus();
+ SetCapture();
+ }
+ return 0;
+ }
+
+ LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(GetCapture() == m_hWnd)
+ {
+ ReleaseCapture();
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ if(::PtInRect(&m_rcLink, pt))
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Navigate();
+ }
+ }
+ return 0;
+ }
+
+ LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(wParam == VK_RETURN || wParam == VK_SPACE)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Navigate();
+ }
+ return 0;
+ }
+
+ LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return DLGC_WANTCHARS;
+ }
+
+ LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ POINT pt = { 0, 0 };
+ GetCursorPos(&pt);
+ ScreenToClient(&pt);
+ if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
+ {
+ return TRUE;
+ }
+ bHandled = FALSE;
+ return FALSE;
+ }
+
+ LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ Invalidate();
+ UpdateWindow();
+ return 0;
+ }
+
+ LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)m_hFontNormal;
+ }
+
+ LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(m_bInternalNormalFont)
+ {
+ ::DeleteObject(m_hFontNormal);
+ m_bInternalNormalFont = false;
+ }
+
+ bool bCreateLinkFont = m_bInternalLinkFont;
+
+ m_hFontNormal = (HFONT)wParam;
+
+ if(bCreateLinkFont || IsAutoCreateLinkFont())
+ CreateLinkFontFromNormal();
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+
+ if((BOOL)lParam)
+ {
+ Invalidate();
+ UpdateWindow();
+ }
+
+ return 0;
+ }
+
+ LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ // If the control is subclassed or superclassed, this message can cause
+ // repainting without WM_PAINT. We don't use this state, so just do nothing.
+ return 0;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+ pT->Invalidate();
+ return 0;
+ }
+
+// Implementation
+ void Init()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ // Check if we should paint a label
+ const int cchBuff = 8;
+ TCHAR szBuffer[cchBuff] = { 0 };
+ if(::GetClassName(m_hWnd, szBuffer, cchBuff))
+ {
+ if(lstrcmpi(szBuffer, _T("static")) == 0)
+ {
+ ModifyStyle(0, SS_NOTIFY); // we need this
+ DWORD dwStyle = GetStyle() & 0x000000FF;
+#ifndef _WIN32_WCE
+ if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT ||
+ dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME ||
+ dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW ||
+ dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE)
+#else // CE specific
+ if(dwStyle == SS_ICON || dwStyle == SS_BITMAP)
+#endif // _WIN32_WCE
+ m_bPaintLabel = false;
+ }
+ }
+
+ // create or load a cursor
+#if (WINVER >= 0x0500) || defined(_WIN32_WCE)
+ m_hCursor = ::LoadCursor(NULL, IDC_HAND);
+#else
+ m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane);
+#endif
+ ATLASSERT(m_hCursor != NULL);
+
+ // set fonts
+ if(m_bPaintLabel)
+ {
+ if(m_hFontNormal == NULL)
+ {
+ m_hFontNormal = AtlCreateControlFont();
+ m_bInternalNormalFont = true;
+ }
+
+ if(m_hFontLink == NULL)
+ CreateLinkFontFromNormal();
+ }
+
+#ifndef _WIN32_WCE
+ // create a tool tip
+ m_tip.Create(m_hWnd);
+ ATLASSERT(m_tip.IsWindow());
+#endif // !_WIN32_WCE
+
+ // set label (defaults to window text)
+ if(m_lpstrLabel == NULL)
+ {
+ int nLen = GetWindowTextLength();
+ if(nLen > 0)
+ {
+ ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]);
+ if(m_lpstrLabel != NULL)
+ ATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0);
+ }
+ }
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelRect();
+
+ // set hyperlink (defaults to label), or just activate tool tip if already set
+ if(m_lpstrHyperLink == NULL && !IsCommandButton())
+ {
+ if(m_lpstrLabel != NULL)
+ SetHyperLink(m_lpstrLabel);
+ }
+#ifndef _WIN32_WCE
+ else
+ {
+ m_tip.Activate(TRUE);
+ m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
+ }
+#endif // !_WIN32_WCE
+
+ // set link colors
+ if(m_bPaintLabel)
+ {
+ CRegKeyEx rk;
+ LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
+ if(lRet == ERROR_SUCCESS)
+ {
+ const int cchValue = 12;
+ TCHAR szValue[cchValue] = { 0 };
+ ULONG ulCount = cchValue;
+ lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount);
+ if(lRet == ERROR_SUCCESS)
+ {
+ COLORREF clr = pT->_ParseColorString(szValue);
+ ATLASSERT(clr != CLR_INVALID);
+ if(clr != CLR_INVALID)
+ m_clrLink = clr;
+ }
+
+ ulCount = cchValue;
+ lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount);
+ if(lRet == ERROR_SUCCESS)
+ {
+ COLORREF clr = pT->_ParseColorString(szValue);
+ ATLASSERT(clr != CLR_INVALID);
+ if(clr != CLR_INVALID)
+ m_clrVisited = clr;
+ }
+ }
+ }
+ }
+
+ static COLORREF _ParseColorString(LPTSTR lpstr)
+ {
+ int c[3] = { -1, -1, -1 };
+ LPTSTR p = NULL;
+ for(int i = 0; i < 2; i++)
+ {
+ for(p = lpstr; *p != _T('\0'); p = ::CharNext(p))
+ {
+ if(*p == _T(','))
+ {
+ *p = _T('\0');
+ c[i] = T::_xttoi(lpstr);
+ lpstr = &p[1];
+ break;
+ }
+ }
+ if(c[i] == -1)
+ return CLR_INVALID;
+ }
+ if(*lpstr == _T('\0'))
+ return CLR_INVALID;
+ c[2] = T::_xttoi(lpstr);
+
+ return RGB(c[0], c[1], c[2]);
+ }
+
+ bool CalcLabelRect()
+ {
+ if(!::IsWindow(m_hWnd))
+ return false;
+ if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
+ return false;
+
+ CClientDC dc(m_hWnd);
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ m_rcLink = rcClient;
+ if(!m_bPaintLabel)
+ return true;
+
+ if(IsUsingTags())
+ {
+ // find tags and label parts
+ LPTSTR lpstrLeft = NULL;
+ int cchLeft = 0;
+ LPTSTR lpstrLink = NULL;
+ int cchLink = 0;
+ LPTSTR lpstrRight = NULL;
+ int cchRight = 0;
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
+ ATLASSERT(lpstrLink != NULL);
+ ATLASSERT(cchLink > 0);
+
+ // get label part rects
+ HFONT hFontOld = dc.SelectFont(m_hFontNormal);
+
+ UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+
+ RECT rcLeft = rcClient;
+ if(lpstrLeft != NULL)
+ dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
+
+ dc.SelectFont(m_hFontLink);
+ RECT rcLink = rcClient;
+ if(lpstrLeft != NULL)
+ rcLink.left = rcLeft.right;
+ dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
+
+ dc.SelectFont(hFontOld);
+
+ m_rcLink = rcLink;
+ }
+ else
+ {
+ HFONT hOldFont = NULL;
+ if(m_hFontLink != NULL)
+ hOldFont = dc.SelectFont(m_hFontLink);
+ LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
+ DWORD dwStyle = GetStyle();
+ UINT uFormat = DT_LEFT;
+ if (dwStyle & SS_CENTER)
+ uFormat = DT_CENTER;
+ else if (dwStyle & SS_RIGHT)
+ uFormat = DT_RIGHT;
+ uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+ dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT);
+ if(m_hFontLink != NULL)
+ dc.SelectFont(hOldFont);
+ if (dwStyle & SS_CENTER)
+ {
+ int dx = (rcClient.right - m_rcLink.right) / 2;
+ ::OffsetRect(&m_rcLink, dx, 0);
+ }
+ else if (dwStyle & SS_RIGHT)
+ {
+ int dx = rcClient.right - m_rcLink.right;
+ ::OffsetRect(&m_rcLink, dx, 0);
+ }
+ }
+
+ return true;
+ }
+
+ void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const
+ {
+ lpstrLeft = NULL;
+ cchLeft = 0;
+ lpstrLink = NULL;
+ cchLink = 0;
+ lpstrRight = NULL;
+ cchRight = 0;
+
+ LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
+ int cchText = lstrlen(lpstrText);
+ bool bOutsideLink = true;
+ for(int i = 0; i < cchText; i++)
+ {
+ if(lpstrText[i] != _T('<'))
+ continue;
+
+ if(bOutsideLink)
+ {
+ if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T("<A>"), 3) == CSTR_EQUAL)
+ {
+ if(i > 0)
+ {
+ lpstrLeft = lpstrText;
+ cchLeft = i;
+ }
+ lpstrLink = &lpstrText[i + 3];
+ bOutsideLink = false;
+ }
+ }
+ else
+ {
+ if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T("</A>"), 4) == CSTR_EQUAL)
+ {
+ cchLink = i - 3 - cchLeft;
+ if(lpstrText[i + 4] != 0)
+ {
+ lpstrRight = &lpstrText[i + 4];
+ cchRight = cchText - (i + 4);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ void DoEraseBackground(CDCHandle dc)
+ {
+ HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd);
+ if(hBrush != NULL)
+ {
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+ dc.FillRect(&rect, hBrush);
+ }
+ }
+
+ void DoPaint(CDCHandle dc)
+ {
+ if(IsUsingTags())
+ {
+ // find tags and label parts
+ LPTSTR lpstrLeft = NULL;
+ int cchLeft = 0;
+ LPTSTR lpstrLink = NULL;
+ int cchLink = 0;
+ LPTSTR lpstrRight = NULL;
+ int cchRight = 0;
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
+
+ // get label part rects
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+
+ dc.SetBkMode(TRANSPARENT);
+ HFONT hFontOld = dc.SelectFont(m_hFontNormal);
+
+ UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+
+ if(lpstrLeft != NULL)
+ dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat);
+
+ COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
+ if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
+ dc.SelectFont(m_hFontLink);
+ else
+ dc.SelectFont(m_hFontNormal);
+
+ dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat);
+
+ dc.SetTextColor(clrOld);
+ dc.SelectFont(m_hFontNormal);
+ if(lpstrRight != NULL)
+ {
+ RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom };
+ dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat);
+ }
+
+ if(GetFocus() == m_hWnd)
+ dc.DrawFocusRect(&m_rcLink);
+
+ dc.SelectFont(hFontOld);
+ }
+ else
+ {
+ dc.SetBkMode(TRANSPARENT);
+ COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
+
+ HFONT hFontOld = NULL;
+ if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
+ hFontOld = dc.SelectFont(m_hFontLink);
+ else
+ hFontOld = dc.SelectFont(m_hFontNormal);
+
+ LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
+
+ DWORD dwStyle = GetStyle();
+ UINT uFormat = DT_LEFT;
+ if (dwStyle & SS_CENTER)
+ uFormat = DT_CENTER;
+ else if (dwStyle & SS_RIGHT)
+ uFormat = DT_RIGHT;
+ uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
+
+ dc.DrawText(lpstrText, -1, &m_rcLink, uFormat);
+
+ if(GetFocus() == m_hWnd)
+ dc.DrawFocusRect(&m_rcLink);
+
+ dc.SetTextColor(clrOld);
+ dc.SelectFont(hFontOld);
+ }
+ }
+
+#ifndef _WIN32_WCE
+ BOOL StartTrackMouseLeave()
+ {
+ TRACKMOUSEEVENT tme = { 0 };
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = m_hWnd;
+ return _TrackMouseEvent(&tme);
+ }
+#endif // !_WIN32_WCE
+
+// Implementation helpers
+ bool IsUnderlined() const
+ {
+ return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0);
+ }
+
+ bool IsNotUnderlined() const
+ {
+ return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0);
+ }
+
+ bool IsUnderlineHover() const
+ {
+ return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0);
+ }
+
+ bool IsCommandButton() const
+ {
+ return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0);
+ }
+
+ bool IsNotifyButton() const
+ {
+ return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON);
+ }
+
+ bool IsUsingTags() const
+ {
+ return ((m_dwExtendedStyle & HLINK_USETAGS) != 0);
+ }
+
+ bool IsUsingTagsBold() const
+ {
+ return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD);
+ }
+
+ bool IsUsingToolTip() const
+ {
+ return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0);
+ }
+
+ bool IsAutoCreateLinkFont() const
+ {
+ return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT);
+ }
+
+ bool IsSingleLine() const
+ {
+ return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE);
+ }
+
+ static int _xttoi(const TCHAR* nptr)
+ {
+#ifndef _ATL_MIN_CRT
+ return _ttoi(nptr);
+#else // _ATL_MIN_CRT
+ while(*nptr == _T(' ')) // skip spaces
+ ++nptr;
+
+ int c = (int)(_TUCHAR)*nptr++;
+ int sign = c; // save sign indication
+ if (c == _T('-') || c == _T('+'))
+ c = (int)(_TUCHAR)*nptr++; // skip sign
+
+ int total = 0;
+ while((TCHAR)c >= _T('0') && (TCHAR)c <= _T('9'))
+ {
+ total = 10 * total + ((TCHAR)c - _T('0')); // accumulate digit
+ c = (int)(_TUCHAR)*nptr++; // get next char
+ }
+
+ // return result, negated if necessary
+ return ((TCHAR)sign != _T('-')) ? total : -total;
+#endif // _ATL_MIN_CRT
+ }
+};
+
+class CHyperLink : public CHyperLinkImpl<CHyperLink>
+{
+public:
+ DECLARE_WND_CLASS(_T("WTL_HyperLink"))
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWaitCursor - displays a wait cursor
+
+class CWaitCursor
+{
+public:
+// Data
+ HCURSOR m_hWaitCursor;
+ HCURSOR m_hOldCursor;
+ bool m_bInUse;
+
+// Constructor/destructor
+ CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)
+ {
+ HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance();
+ m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);
+ ATLASSERT(m_hWaitCursor != NULL);
+
+ if(bSet)
+ Set();
+ }
+
+ ~CWaitCursor()
+ {
+ Restore();
+ }
+
+// Methods
+ bool Set()
+ {
+ if(m_bInUse)
+ return false;
+ m_hOldCursor = ::SetCursor(m_hWaitCursor);
+ m_bInUse = true;
+ return true;
+ }
+
+ bool Restore()
+ {
+ if(!m_bInUse)
+ return false;
+ ::SetCursor(m_hOldCursor);
+ m_bInUse = false;
+ return true;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCustomWaitCursor - for custom and animated cursors
+
+class CCustomWaitCursor : public CWaitCursor
+{
+public:
+// Constructor/destructor
+ CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) :
+ CWaitCursor(false, IDC_WAIT, true)
+ {
+ if(hInstance == NULL)
+ hInstance = ModuleHelper::GetResourceInstance();
+ m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
+
+ if(bSet)
+ Set();
+ }
+
+ ~CCustomWaitCursor()
+ {
+ Restore();
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
+ ::DestroyCursor(m_hWaitCursor);
+#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMultiPaneStatusBarCtrl - Status Bar with multiple panes
+
+template <class T, class TBase = CStatusBarCtrl>
+class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase >
+{
+public:
+ DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
+
+// Data
+ enum { m_cxPaneMargin = 3 };
+
+ int m_nPanes;
+ int* m_pPane;
+
+// Constructor/destructor
+ CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL)
+ { }
+
+ ~CMultiPaneStatusBarCtrlImpl()
+ {
+ delete [] m_pPane;
+ }
+
+// Methods
+ HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
+ {
+#if (_MSC_VER >= 1300)
+ return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase > _baseClass;
+ return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID);
+#endif // !(_MSC_VER >= 1300)
+ }
+
+ HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
+ {
+ const int cchMax = 128; // max text length is 127 for status bars (+1 for null)
+ TCHAR szText[cchMax];
+ szText[0] = 0;
+ ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
+ return Create(hWndParent, szText, dwStyle, nID);
+ }
+
+ BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPanes > 0);
+
+ m_nPanes = nPanes;
+ delete [] m_pPane;
+ m_pPane = NULL;
+
+ ATLTRY(m_pPane = new int[nPanes]);
+ ATLASSERT(m_pPane != NULL);
+ if(m_pPane == NULL)
+ return FALSE;
+
+ CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ int* pPanesPos = buff.Allocate(nPanes);
+ ATLASSERT(pPanesPos != NULL);
+ if(pPanesPos == NULL)
+ return FALSE;
+
+ SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int));
+
+ // get status bar DC and set font
+ CClientDC dc(m_hWnd);
+ HFONT hOldFont = dc.SelectFont(GetFont());
+
+ // get status bar borders
+ int arrBorders[3] = { 0 };
+ GetBorders(arrBorders);
+
+ const int cchBuff = 128;
+ TCHAR szBuff[cchBuff] = { 0 };
+ SIZE size = { 0, 0 };
+ int cxLeft = arrBorders[0];
+
+ // calculate right edge of each part
+ for(int i = 0; i < nPanes; i++)
+ {
+ if(pPanes[i] == ID_DEFAULT_PANE)
+ {
+ // make very large, will be resized later
+ pPanesPos[i] = INT_MAX / 2;
+ }
+ else
+ {
+ ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);
+ dc.GetTextExtent(szBuff, lstrlen(szBuff), &size);
+ T* pT = static_cast<T*>(this);
+ pT;
+ pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin;
+ }
+ cxLeft = pPanesPos[i];
+ }
+
+ BOOL bRet = SetParts(nPanes, pPanesPos);
+
+ if(bRet && bSetText)
+ {
+ for(int i = 0; i < nPanes; i++)
+ {
+ if(pPanes[i] != ID_DEFAULT_PANE)
+ {
+ ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);
+ SetPaneText(m_pPane[i], szBuff);
+ }
+ }
+ }
+
+ dc.SelectFont(hOldFont);
+ return bRet;
+ }
+
+ bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return false;
+
+ int nLength = GetTextLength(nIndex, pnType);
+ if(pcchLength != NULL)
+ *pcchLength = nLength;
+
+ return true;
+ }
+
+ BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ int nLength = GetText(nIndex, lpstrText, pnType);
+ if(pcchLength != NULL)
+ *pcchLength = nLength;
+
+ return TRUE;
+ }
+
+ BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ return SetText(nIndex, lpstrText, nType);
+ }
+
+ BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ return GetRect(nIndex, lpRect);
+ }
+
+ BOOL SetPaneWidth(int nPaneID, int cxWidth)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ // get pane positions
+ CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ int* pPanesPos = buff.Allocate(m_nPanes);
+ if(pPanesPos == NULL)
+ return FALSE;
+ GetParts(m_nPanes, pPanesPos);
+ // calculate offset
+ int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]);
+ int cxOff = cxWidth - cxPaneWidth;
+ // find variable width pane
+ int nDef = m_nPanes;
+ for(int i = 0; i < m_nPanes; i++)
+ {
+ if(m_pPane[i] == ID_DEFAULT_PANE)
+ {
+ nDef = i;
+ break;
+ }
+ }
+ // resize
+ if(nIndex < nDef) // before default pane
+ {
+ for(int i = nIndex; i < nDef; i++)
+ pPanesPos[i] += cxOff;
+
+ }
+ else // after default one
+ {
+ for(int i = nDef; i < nIndex; i++)
+ pPanesPos[i] -= cxOff;
+ }
+ // set pane postions
+ return SetParts(m_nPanes, pPanesPos);
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ GetTipText(nIndex, lpstrText, nSize);
+ return TRUE;
+ }
+
+ BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ SetTipText(nIndex, lpstrText);
+ return TRUE;
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
+ BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ hIcon = GetIcon(nIndex);
+ return TRUE;
+ }
+
+ BOOL SetPaneIcon(int nPaneID, HICON hIcon)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ int nIndex = GetPaneIndexFromID(nPaneID);
+ if(nIndex == -1)
+ return FALSE;
+
+ return SetIcon(nIndex, hIcon);
+ }
+#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(wParam != SIZE_MINIMIZED && m_nPanes > 0)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdatePanesLayout();
+ }
+ return lRet;
+ }
+
+// Implementation
+ BOOL UpdatePanesLayout()
+ {
+ // get pane positions
+ CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ int* pPanesPos = buff.Allocate(m_nPanes);
+ ATLASSERT(pPanesPos != NULL);
+ if(pPanesPos == NULL)
+ return FALSE;
+ int nRet = GetParts(m_nPanes, pPanesPos);
+ ATLASSERT(nRet == m_nPanes);
+ if(nRet != m_nPanes)
+ return FALSE;
+ // calculate offset
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ int cxOff = rcClient.right - pPanesPos[m_nPanes - 1];
+#ifndef _WIN32_WCE
+ // Move panes left if size grip box is present
+ if((GetStyle() & SBARS_SIZEGRIP) != 0)
+ cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE);
+#endif // !_WIN32_WCE
+ // find variable width pane
+ int i;
+ for(i = 0; i < m_nPanes; i++)
+ {
+ if(m_pPane[i] == ID_DEFAULT_PANE)
+ break;
+ }
+ // resize all panes from the variable one to the right
+ if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1]))
+ {
+ for(; i < m_nPanes; i++)
+ pPanesPos[i] += cxOff;
+ }
+ // set pane postions
+ return SetParts(m_nPanes, pPanesPos);
+ }
+
+ int GetPaneIndexFromID(int nPaneID) const
+ {
+ for(int i = 0; i < m_nPanes; i++)
+ {
+ if(m_pPane[i] == nPaneID)
+ return i;
+ }
+
+ return -1; // not found
+ }
+};
+
+class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPaneContainer - provides header with title and close button for panes
+
+// pane container extended styles
+#define PANECNT_NOCLOSEBUTTON 0x00000001
+#define PANECNT_VERTICAL 0x00000002
+#define PANECNT_FLATBORDER 0x00000004
+#define PANECNT_NOBORDER 0x00000008
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T >
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, 0, -1)
+
+// Constants
+ enum
+ {
+ m_cxyBorder = 2,
+ m_cxyTextOffset = 4,
+ m_cxyBtnOffset = 1,
+
+ m_cchTitle = 80,
+
+ m_cxImageTB = 13,
+ m_cyImageTB = 11,
+ m_cxyBtnAddTB = 7,
+
+ m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset,
+
+ m_xBtnImageLeft = 6,
+ m_yBtnImageTop = 5,
+ m_xBtnImageRight = 12,
+ m_yBtnImageBottom = 11,
+
+ m_nCloseBtnID = ID_PANE_CLOSE
+ };
+
+// Data members
+ CToolBarCtrl m_tb;
+ ATL::CWindow m_wndClient;
+ int m_cxyHeader;
+ TCHAR m_szTitle[m_cchTitle];
+ DWORD m_dwExtendedStyle; // Pane container specific extended styles
+ HFONT m_hFont;
+ bool m_bInternalFont;
+
+
+// Constructor
+ CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false)
+ {
+ m_szTitle[0] = 0;
+ }
+
+// Attributes
+ DWORD GetPaneContainerExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ if(m_hWnd != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ bool bUpdate = false;
+
+ if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button
+ {
+ pT->CreateCloseButton();
+ bUpdate = true;
+ }
+ else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button
+ {
+ pT->DestroyCloseButton();
+ bUpdate = true;
+ }
+
+ if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation
+ {
+ pT->CalcSize();
+ bUpdate = true;
+ }
+
+ if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) !=
+ (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border
+ {
+ bUpdate = true;
+ }
+
+ if(bUpdate)
+ pT->UpdateLayout();
+ }
+ return dwPrevStyle;
+ }
+
+ HWND GetClient() const
+ {
+ return m_wndClient;
+ }
+
+ HWND SetClient(HWND hWndClient)
+ {
+ HWND hWndOldClient = m_wndClient;
+ m_wndClient = hWndClient;
+ if(m_hWnd != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+ return hWndOldClient;
+ }
+
+ BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const
+ {
+ ATLASSERT(lpstrTitle != NULL);
+
+ errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE);
+
+ return (nRet == 0 || nRet == STRUNCATE);
+ }
+
+ BOOL SetTitle(LPCTSTR lpstrTitle)
+ {
+ ATLASSERT(lpstrTitle != NULL);
+
+ errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);
+ bool bRet = (nRet == 0 || nRet == STRUNCATE);
+ if(bRet && m_hWnd != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+
+ return bRet;
+ }
+
+ int GetTitleLength() const
+ {
+ return lstrlen(m_szTitle);
+ }
+
+// Methods
+ HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
+ {
+ if(lpstrTitle != NULL)
+ SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);
+#if (_MSC_VER >= 1300)
+ return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
+ return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
+#endif // !(_MSC_VER >= 1300)
+ }
+
+ HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
+ {
+ if(uTitleID != 0U)
+ ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle);
+#if (_MSC_VER >= 1300)
+ return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
+#else // !(_MSC_VER >= 1300)
+ typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
+ return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
+#endif // !(_MSC_VER >= 1300)
+ }
+
+ BOOL EnableCloseButton(BOOL bEnable)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE;
+ }
+
+ void UpdateLayout()
+ {
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout(rcClient.right, rcClient.bottom);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CPaneContainerImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
+ MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+ MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+ FORWARD_NOTIFICATIONS()
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_hFont == NULL)
+ {
+ // The same as AtlCreateControlFont() for horizontal pane
+#ifndef _WIN32_WCE
+ LOGFONT lf = { 0 };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);
+ if(IsVertical())
+ lf.lfEscapement = 900; // 90 degrees
+ m_hFont = ::CreateFontIndirect(&lf);
+#else // CE specific
+ m_hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
+ if(IsVertical())
+ {
+ CLogFont lf(m_hFont);
+ lf.lfEscapement = 900; // 90 degrees
+ m_hFont = ::CreateFontIndirect(&lf);
+ }
+#endif // _WIN32_WCE
+ m_bInternalFont = true;
+ }
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcSize();
+
+ if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)
+ pT->CreateCloseButton();
+
+ return 0;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_bInternalFont)
+ {
+ ::DeleteObject(m_hFont);
+ m_hFont = NULL;
+ m_bInternalFont = false;
+ }
+
+ return 0;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ return 0;
+ }
+
+ LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_wndClient.m_hWnd != NULL)
+ m_wndClient.SetFocus();
+ return 0;
+ }
+
+ LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)m_hFont;
+ }
+
+ LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(m_bInternalFont)
+ {
+ ::DeleteObject(m_hFont);
+ m_bInternalFont = false;
+ }
+
+ m_hFont = (HFONT)wParam;
+
+ T* pT = static_cast<T*>(this);
+ pT->CalcSize();
+
+ if((BOOL)lParam != FALSE)
+ pT->UpdateLayout();
+
+ return 0;
+ }
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background needed
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ if(wParam != NULL)
+ {
+ pT->DrawPaneTitle((HDC)wParam);
+
+ if(m_wndClient.m_hWnd == NULL) // no client window
+ pT->DrawPane((HDC)wParam);
+ }
+ else
+ {
+ CPaintDC dc(m_hWnd);
+ pT->DrawPaneTitle(dc.m_hDC);
+
+ if(m_wndClient.m_hWnd == NULL) // no client window
+ pT->DrawPane(dc.m_hDC);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(m_tb.m_hWnd == NULL)
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+
+ T* pT = static_cast<T*>(this);
+ pT;
+ LPNMHDR lpnmh = (LPNMHDR)lParam;
+ LRESULT lRet = 0;
+
+ // pass toolbar custom draw notifications to the base class
+ if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd)
+ lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled);
+#ifndef _WIN32_WCE
+ // tooltip notifications come with the tooltip window handle and button ID,
+ // pass them to the parent if we don't handle them
+ else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID)
+ bHandled = pT->GetToolTipText(lpnmh);
+#endif // !_WIN32_WCE
+ // only let notifications not from the toolbar go to the parent
+ else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID)
+ bHandled = FALSE;
+
+ return lRet;
+ }
+
+ LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ // if command comes from the close button, substitute HWND of the pane container instead
+ if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd)
+ return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+// Custom draw overrides
+ DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
+ {
+ return CDRF_NOTIFYITEMDRAW; // we need per-item notifications
+ }
+
+ DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
+ {
+ CDCHandle dc = lpNMCustomDraw->hdc;
+#if (_WIN32_IE >= 0x0400)
+ RECT& rc = lpNMCustomDraw->rc;
+#else // !(_WIN32_IE >= 0x0400)
+ RECT rc;
+ m_tb.GetItemRect(0, &rc);
+#endif // !(_WIN32_IE >= 0x0400)
+
+ dc.FillRect(&rc, COLOR_3DFACE);
+
+ return CDRF_NOTIFYPOSTPAINT;
+ }
+
+ DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
+ {
+ CDCHandle dc = lpNMCustomDraw->hdc;
+#if (_WIN32_IE >= 0x0400)
+ RECT& rc = lpNMCustomDraw->rc;
+#else // !(_WIN32_IE >= 0x0400)
+ RECT rc = { 0 };
+ m_tb.GetItemRect(0, &rc);
+#endif // !(_WIN32_IE >= 0x0400)
+
+ RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 };
+ ::OffsetRect(&rcImage, rc.left, rc.top);
+ T* pT = static_cast<T*>(this);
+
+ if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0)
+ {
+ RECT rcShadow = rcImage;
+ ::OffsetRect(&rcShadow, 1, 1);
+ CPen pen1;
+ pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));
+ pT->DrawButtonImage(dc, rcShadow, pen1);
+ CPen pen2;
+ pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));
+ pT->DrawButtonImage(dc, rcImage, pen2);
+ }
+ else
+ {
+ if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0)
+ ::OffsetRect(&rcImage, 1, 1);
+ CPen pen;
+ pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT));
+ pT->DrawButtonImage(dc, rcImage, pen);
+ }
+
+ return CDRF_DODEFAULT; // continue with the default item painting
+ }
+
+// Implementation - overrideable methods
+ void UpdateLayout(int cxWidth, int cyHeight)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ RECT rect = { 0 };
+
+ if(IsVertical())
+ {
+ ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight);
+ if(m_tb.m_hWnd != NULL)
+ m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ if(m_wndClient.m_hWnd != NULL)
+ m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER);
+ else
+ rect.right = cxWidth;
+ }
+ else
+ {
+ ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader);
+ if(m_tb.m_hWnd != NULL)
+ m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ if(m_wndClient.m_hWnd != NULL)
+ m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER);
+ else
+ rect.bottom = cyHeight;
+ }
+
+ InvalidateRect(&rect);
+ }
+
+ void CreateCloseButton()
+ {
+ ATLASSERT(m_tb.m_hWnd == NULL);
+ // create toolbar for the "x" button
+ m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0);
+ ATLASSERT(m_tb.IsWindow());
+
+ if(m_tb.m_hWnd != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+
+ m_tb.SetButtonStructSize();
+
+ TBBUTTON tbbtn = { 0 };
+ tbbtn.idCommand = pT->m_nCloseBtnID;
+ tbbtn.fsState = TBSTATE_ENABLED;
+ tbbtn.fsStyle = TBSTYLE_BUTTON;
+ m_tb.AddButtons(1, &tbbtn);
+
+ m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB);
+ m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB);
+
+ if(IsVertical())
+ m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOACTIVATE);
+ else
+ m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+ }
+ }
+
+ void DestroyCloseButton()
+ {
+ if(m_tb.m_hWnd != NULL)
+ m_tb.DestroyWindow();
+ }
+
+ void CalcSize()
+ {
+ T* pT = static_cast<T*>(this);
+ CFontHandle font = pT->GetTitleFont();
+ if(font.IsNull())
+ font = (HFONT)::GetStockObject(SYSTEM_FONT);
+ LOGFONT lf = { 0 };
+ font.GetLogFont(lf);
+ if(IsVertical())
+ {
+ m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder;
+ }
+ else
+ {
+ int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset;
+ int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset;
+ m_cxyHeader = max(cyFont, cyBtn);
+ }
+ }
+
+ HFONT GetTitleFont() const
+ {
+ return m_hFont;
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetToolTipText(LPNMHDR /*lpnmh*/)
+ {
+ return FALSE;
+ }
+#endif // !_WIN32_WCE
+
+ void DrawPaneTitle(CDCHandle dc)
+ {
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+
+ UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST;
+ if(IsVertical())
+ {
+ rect.right = rect.left + m_cxyHeader;
+ uBorder |= BF_BOTTOM;
+ }
+ else
+ {
+ rect.bottom = rect.top + m_cxyHeader;
+ uBorder |= BF_RIGHT;
+ }
+
+ if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0)
+ {
+ if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0)
+ uBorder |= BF_FLAT;
+ dc.DrawEdge(&rect, EDGE_ETCHED, uBorder);
+ }
+ dc.FillRect(&rect, COLOR_3DFACE);
+
+ // draw title text
+ dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
+ dc.SetBkMode(TRANSPARENT);
+ T* pT = static_cast<T*>(this);
+ HFONT hFontOld = dc.SelectFont(pT->GetTitleFont());
+#ifdef _WIN32_WCE
+ const UINT DT_END_ELLIPSIS = 0;
+#endif // _WIN32_WCE
+
+ if(IsVertical())
+ {
+ rect.top += m_cxyTextOffset;
+ rect.bottom -= m_cxyTextOffset;
+ if(m_tb.m_hWnd != NULL)
+ rect.top += m_cxToolBar;;
+
+ RECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top };
+ int cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT);
+ RECT rcText = { 0 };
+ rcText.left = (rect.right - rect.left - cxFont) / 2;
+ rcText.right = rcText.left + (rect.bottom - rect.top);
+ rcText.top = rect.bottom;
+ rcText.bottom = rect.top;
+ dc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);
+ }
+ else
+ {
+ rect.left += m_cxyTextOffset;
+ rect.right -= m_cxyTextOffset;
+ if(m_tb.m_hWnd != NULL)
+ rect.right -= m_cxToolBar;;
+
+ dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
+ }
+
+ dc.SelectFont(hFontOld);
+ }
+
+ // called only if pane is empty
+ void DrawPane(CDCHandle dc)
+ {
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+ if(IsVertical())
+ rect.left += m_cxyHeader;
+ else
+ rect.top += m_cxyHeader;
+ if((GetExStyle() & WS_EX_CLIENTEDGE) == 0)
+ dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ dc.FillRect(&rect, COLOR_APPWORKSPACE);
+ }
+
+ // drawing helper - draws "x" button image
+ void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen)
+ {
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+ HPEN hPenOld = dc.SelectPen(hPen);
+
+ dc.MoveTo(rcImage.left, rcImage.top);
+ dc.LineTo(rcImage.right, rcImage.bottom);
+ dc.MoveTo(rcImage.left + 1, rcImage.top);
+ dc.LineTo(rcImage.right + 1, rcImage.bottom);
+
+ dc.MoveTo(rcImage.left, rcImage.bottom - 1);
+ dc.LineTo(rcImage.right, rcImage.top - 1);
+ dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);
+ dc.LineTo(rcImage.right + 1, rcImage.top - 1);
+
+ dc.SelectPen(hPenOld);
+#else // (_WIN32_WCE < 400)
+ rcImage;
+ hPen;
+ // no support for the "x" button image
+#endif // (_WIN32_WCE < 400)
+ }
+
+ bool IsVertical() const
+ {
+ return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0);
+ }
+};
+
+class CPaneContainer : public CPaneContainerImpl<CPaneContainer>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSortListViewCtrl - implements sorting for a listview control
+
+// sort listview extended styles
+#define SORTLV_USESHELLBITMAPS 0x00000001
+
+// Notification sent to parent when sort column is changed by user clicking header.
+#define SLVN_SORTCHANGED LVN_LAST
+
+// A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification
+typedef struct tagNMSORTLISTVIEW
+{
+ NMHDR hdr;
+ int iNewSortColumn;
+ int iOldSortColumn;
+} NMSORTLISTVIEW, *LPNMSORTLISTVIEW;
+
+// Column sort types. Can be set on a per-column basis with the SetColumnSortType method.
+enum
+{
+ LVCOLSORT_NONE,
+ LVCOLSORT_TEXT, // default
+ LVCOLSORT_TEXTNOCASE,
+ LVCOLSORT_LONG,
+ LVCOLSORT_DOUBLE,
+ LVCOLSORT_DECIMAL,
+ LVCOLSORT_DATETIME,
+ LVCOLSORT_DATE,
+ LVCOLSORT_TIME,
+ LVCOLSORT_CUSTOM,
+ LVCOLSORT_LAST = LVCOLSORT_CUSTOM
+};
+
+
+template <class T>
+class CSortListViewImpl
+{
+public:
+ enum
+ {
+ m_cchCmpTextMax = 32, // overrideable
+ m_cxSortImage = 16,
+ m_cySortImage = 15,
+ m_cxSortArrow = 11,
+ m_cySortArrow = 6,
+ m_iSortUp = 0, // index of sort bitmaps
+ m_iSortDown = 1,
+ m_nShellSortUpID = 133
+ };
+
+ // passed to LVCompare functions as lParam1 and lParam2
+ struct LVCompareParam
+ {
+ int iItem;
+ DWORD_PTR dwItemData;
+ union
+ {
+ long lValue;
+ double dblValue;
+ DECIMAL decValue;
+ LPCTSTR pszValue;
+ };
+ };
+
+ // passed to LVCompare functions as the lParamSort parameter
+ struct LVSortInfo
+ {
+ T* pT;
+ int iSortCol;
+ bool bDescending;
+ };
+
+ bool m_bSortDescending;
+ bool m_bCommCtrl6;
+ int m_iSortColumn;
+ CBitmap m_bmSort[2];
+ int m_fmtOldSortCol;
+ HBITMAP m_hbmOldSortCol;
+ DWORD m_dwSortLVExtendedStyle;
+ ATL::CSimpleArray<WORD> m_arrColSortType;
+ bool m_bUseWaitCursor;
+
+ CSortListViewImpl() :
+ m_bSortDescending(false),
+ m_bCommCtrl6(false),
+ m_iSortColumn(-1),
+ m_fmtOldSortCol(0),
+ m_hbmOldSortCol(NULL),
+ m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS),
+ m_bUseWaitCursor(true)
+ {
+#ifndef _WIN32_WCE
+ DWORD dwMajor = 0;
+ DWORD dwMinor = 0;
+ HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
+ m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6;
+#endif // !_WIN32_WCE
+ }
+
+// Attributes
+ void SetSortColumn(int iCol)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ CHeaderCtrl header = pT->GetHeader();
+ ATLASSERT(header.m_hWnd != NULL);
+ ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize());
+
+ int iOldSortCol = m_iSortColumn;
+ m_iSortColumn = iCol;
+ if(m_bCommCtrl6)
+ {
+#ifndef HDF_SORTUP
+ const int HDF_SORTUP = 0x0400;
+#endif // HDF_SORTUP
+#ifndef HDF_SORTDOWN
+ const int HDF_SORTDOWN = 0x0200;
+#endif // HDF_SORTDOWN
+ const int nMask = HDF_SORTUP | HDF_SORTDOWN;
+ HDITEM hditem = { HDI_FORMAT };
+ if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem))
+ {
+ hditem.fmt &= ~nMask;
+ header.SetItem(iOldSortCol, &hditem);
+ }
+ if(iCol >= 0 && header.GetItem(iCol, &hditem))
+ {
+ hditem.fmt &= ~nMask;
+ hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP;
+ header.SetItem(iCol, &hditem);
+ }
+ return;
+ }
+
+ if(m_bmSort[m_iSortUp].IsNull())
+ pT->CreateSortBitmaps();
+
+ // restore previous sort column's bitmap, if any, and format
+ HDITEM hditem = { HDI_BITMAP | HDI_FORMAT };
+ if(iOldSortCol != iCol && iOldSortCol >= 0)
+ {
+ hditem.hbm = m_hbmOldSortCol;
+ hditem.fmt = m_fmtOldSortCol;
+ header.SetItem(iOldSortCol, &hditem);
+ }
+
+ // save new sort column's bitmap and format, and add our sort bitmap
+ if(iCol >= 0 && header.GetItem(iCol, &hditem))
+ {
+ if(iOldSortCol != iCol)
+ {
+ m_fmtOldSortCol = hditem.fmt;
+ m_hbmOldSortCol = hditem.hbm;
+ }
+ hditem.fmt &= ~HDF_IMAGE;
+ hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
+ int i = m_bSortDescending ? m_iSortDown : m_iSortUp;
+ hditem.hbm = m_bmSort[i];
+ header.SetItem(iCol, &hditem);
+ }
+ }
+
+ int GetSortColumn() const
+ {
+ return m_iSortColumn;
+ }
+
+ void SetColumnSortType(int iCol, WORD wType)
+ {
+ ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
+ ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST);
+ m_arrColSortType[iCol] = wType;
+ }
+
+ WORD GetColumnSortType(int iCol) const
+ {
+ ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize());
+ return m_arrColSortType[iCol];
+ }
+
+ int GetColumnCount() const
+ {
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ CHeaderCtrl header = pT->GetHeader();
+ return header.m_hWnd != NULL ? header.GetItemCount() : 0;
+ }
+
+ bool IsSortDescending() const
+ {
+ return m_bSortDescending;
+ }
+
+ DWORD GetSortListViewExtendedStyle() const
+ {
+ return m_dwSortLVExtendedStyle;
+ }
+
+ DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwSortLVExtendedStyle;
+ if(dwMask == 0)
+ m_dwSortLVExtendedStyle = dwExtendedStyle;
+ else
+ m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ return dwPrevStyle;
+ }
+
+// Operations
+ bool DoSortItems(int iCol, bool bDescending = false)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
+
+ WORD wType = m_arrColSortType[iCol];
+ if(wType == LVCOLSORT_NONE)
+ return false;
+
+ int nCount = pT->GetItemCount();
+ if(nCount < 2)
+ {
+ m_bSortDescending = bDescending;
+ SetSortColumn(iCol);
+ return true;
+ }
+
+ CWaitCursor waitCursor(false);
+ if(m_bUseWaitCursor)
+ waitCursor.Set();
+
+ LVCompareParam* pParam = NULL;
+ ATLTRY(pParam = new LVCompareParam[nCount]);
+ PFNLVCOMPARE pFunc = NULL;
+ TCHAR pszTemp[pT->m_cchCmpTextMax];
+ bool bStrValue = false;
+
+ switch(wType)
+ {
+ case LVCOLSORT_TEXT:
+ pFunc = (PFNLVCOMPARE)pT->LVCompareText;
+ case LVCOLSORT_TEXTNOCASE:
+ if(pFunc == NULL)
+ pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase;
+ case LVCOLSORT_CUSTOM:
+ {
+ if(pFunc == NULL)
+ pFunc = (PFNLVCOMPARE)pT->LVCompareCustom;
+
+ for(int i = 0; i < nCount; i++)
+ {
+ pParam[i].iItem = i;
+ pParam[i].dwItemData = pT->GetItemData(i);
+ pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax];
+ pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax);
+ pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
+ }
+ bStrValue = true;
+ }
+ break;
+ case LVCOLSORT_LONG:
+ {
+ pFunc = (PFNLVCOMPARE)pT->LVCompareLong;
+ for(int i = 0; i < nCount; i++)
+ {
+ pParam[i].iItem = i;
+ pParam[i].dwItemData = pT->GetItemData(i);
+ pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
+ pParam[i].lValue = pT->StrToLong(pszTemp);
+ pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
+ }
+ }
+ break;
+ case LVCOLSORT_DOUBLE:
+ {
+ pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
+ for(int i = 0; i < nCount; i++)
+ {
+ pParam[i].iItem = i;
+ pParam[i].dwItemData = pT->GetItemData(i);
+ pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
+ pParam[i].dblValue = pT->StrToDouble(pszTemp);
+ pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
+ }
+ }
+ break;
+ case LVCOLSORT_DECIMAL:
+ {
+ pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal;
+ for(int i = 0; i < nCount; i++)
+ {
+ pParam[i].iItem = i;
+ pParam[i].dwItemData = pT->GetItemData(i);
+ pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
+ pT->StrToDecimal(pszTemp, &pParam[i].decValue);
+ pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
+ }
+ }
+ break;
+ case LVCOLSORT_DATETIME:
+ case LVCOLSORT_DATE:
+ case LVCOLSORT_TIME:
+ {
+ pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
+ DWORD dwFlags = LOCALE_NOUSEROVERRIDE;
+ if(wType == LVCOLSORT_DATE)
+ dwFlags |= VAR_DATEVALUEONLY;
+ else if(wType == LVCOLSORT_TIME)
+ dwFlags |= VAR_TIMEVALUEONLY;
+ for(int i = 0; i < nCount; i++)
+ {
+ pParam[i].iItem = i;
+ pParam[i].dwItemData = pT->GetItemData(i);
+ pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
+ pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags);
+ pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
+ }
+ }
+ break;
+ default:
+ ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n"));
+ break;
+ } // switch(wType)
+
+ ATLASSERT(pFunc != NULL);
+ LVSortInfo lvsi = { pT, iCol, bDescending };
+ bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE);
+ for(int i = 0; i < nCount; i++)
+ {
+ DWORD_PTR dwItemData = pT->GetItemData(i);
+ LVCompareParam* p = (LVCompareParam*)dwItemData;
+ ATLASSERT(p != NULL);
+ if(bStrValue)
+ delete [] (TCHAR*)p->pszValue;
+ pT->SetItemData(i, p->dwItemData);
+ }
+ delete [] pParam;
+
+ if(bRet)
+ {
+ m_bSortDescending = bDescending;
+ SetSortColumn(iCol);
+ }
+
+ if(m_bUseWaitCursor)
+ waitCursor.Restore();
+
+ return bRet;
+ }
+
+ void CreateSortBitmaps()
+ {
+ if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0)
+ {
+ bool bFree = false;
+ LPCTSTR pszModule = _T("shell32.dll");
+ HINSTANCE hShell = ::GetModuleHandle(pszModule);
+
+ if (hShell == NULL)
+ {
+ hShell = ::LoadLibrary(pszModule);
+ bFree = true;
+ }
+
+ if (hShell != NULL)
+ {
+ bool bSuccess = true;
+ for(int i = m_iSortUp; i <= m_iSortDown; i++)
+ {
+ if(!m_bmSort[i].IsNull())
+ m_bmSort[i].DeleteObject();
+ m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i),
+#ifndef _WIN32_WCE
+ IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
+#else // CE specific
+ IMAGE_BITMAP, 0, 0, 0);
+#endif // _WIN32_WCE
+ if(m_bmSort[i].IsNull())
+ {
+ bSuccess = false;
+ break;
+ }
+ }
+ if(bFree)
+ ::FreeLibrary(hShell);
+ if(bSuccess)
+ return;
+ }
+ }
+
+ T* pT = static_cast<T*>(this);
+ for(int i = m_iSortUp; i <= m_iSortDown; i++)
+ {
+ if(!m_bmSort[i].IsNull())
+ m_bmSort[i].DeleteObject();
+
+ CDC dcMem;
+ CClientDC dc(::GetDesktopWindow());
+ dcMem.CreateCompatibleDC(dc.m_hDC);
+ m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage);
+ HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]);
+ RECT rc = {0,0,m_cxSortImage, m_cySortImage};
+ pT->DrawSortBitmap(dcMem.m_hDC, i, &rc);
+ dcMem.SelectBitmap(hbmOld);
+ dcMem.DeleteDC();
+ }
+ }
+
+ void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol)
+ {
+ T* pT = static_cast<T*>(this);
+ int nID = pT->GetDlgCtrlID();
+ NMSORTLISTVIEW nm = { { pT->m_hWnd, nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol };
+ ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm);
+ }
+
+// Overrideables
+ int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/)
+ {
+ // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members.
+ // If item1 > item2 return 1, if item1 < item2 return -1, else return 0.
+ return 0;
+ }
+
+ void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc)
+ {
+ dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE));
+ HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
+ CPen pen;
+ pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW));
+ HPEN hpenOld = dc.SelectPen(pen);
+ POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 };
+ if(iBitmap == m_iSortUp)
+ {
+ POINT pts[3] =
+ {
+ { ptOrg.x + m_cxSortArrow / 2, ptOrg.y },
+ { ptOrg.x, ptOrg.y + m_cySortArrow - 1 },
+ { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 }
+ };
+ dc.Polygon(pts, 3);
+ }
+ else
+ {
+ POINT pts[3] =
+ {
+ { ptOrg.x, ptOrg.y },
+ { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 },
+ { ptOrg.x + m_cxSortArrow - 1, ptOrg.y }
+ };
+ dc.Polygon(pts, 3);
+ }
+ dc.SelectBrush(hbrOld);
+ dc.SelectPen(hpenOld);
+ }
+
+ double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags)
+ {
+ ATLASSERT(lpstr != NULL);
+ if(lpstr == NULL || lpstr[0] == _T('\0'))
+ return 0;
+
+ USES_CONVERSION;
+ HRESULT hRet = E_FAIL;
+ DATE dRet = 0;
+ if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet)))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet);
+ dRet = 0;
+ }
+ return dRet;
+ }
+
+ long StrToLong(LPCTSTR lpstr)
+ {
+ ATLASSERT(lpstr != NULL);
+ if(lpstr == NULL || lpstr[0] == _T('\0'))
+ return 0;
+
+ USES_CONVERSION;
+ HRESULT hRet = E_FAIL;
+ long lRet = 0;
+ if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet)))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet);
+ lRet = 0;
+ }
+ return lRet;
+ }
+
+ double StrToDouble(LPCTSTR lpstr)
+ {
+ ATLASSERT(lpstr != NULL);
+ if(lpstr == NULL || lpstr[0] == _T('\0'))
+ return 0;
+
+ USES_CONVERSION;
+ HRESULT hRet = E_FAIL;
+ double dblRet = 0;
+ if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet)))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet);
+ dblRet = 0;
+ }
+ return dblRet;
+ }
+
+ bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal)
+ {
+ ATLASSERT(lpstr != NULL);
+ ATLASSERT(pDecimal != NULL);
+ if(lpstr == NULL || pDecimal == NULL)
+ return false;
+
+ USES_CONVERSION;
+ HRESULT hRet = E_FAIL;
+ if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal)))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet);
+ pDecimal->Lo64 = 0;
+ pDecimal->Hi32 = 0;
+ pDecimal->signscale = 0;
+ return false;
+ }
+ return true;
+ }
+
+// Overrideable PFNLVCOMPARE functions
+ static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue);
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+
+ static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue);
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+
+ static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = 0;
+ if(pParam1->lValue > pParam2->lValue)
+ nRet = 1;
+ else if(pParam1->lValue < pParam2->lValue)
+ nRet = -1;
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+
+ static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = 0;
+ if(pParam1->dblValue > pParam2->dblValue)
+ nRet = 1;
+ else if(pParam1->dblValue < pParam2->dblValue)
+ nRet = -1;
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+
+ static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol);
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+
+#ifndef _WIN32_WCE
+ static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue);
+ nRet--;
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+#else
+ // Compare mantissas, ignore sign and scale
+ static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight)
+ {
+ if (decLeft.Hi32 < decRight.Hi32)
+ {
+ return -1;
+ }
+ if (decLeft.Hi32 > decRight.Hi32)
+ {
+ return 1;
+ }
+ // Here, decLeft.Hi32 == decRight.Hi32
+ if (decLeft.Lo64 < decRight.Lo64)
+ {
+ return -1;
+ }
+ if (decLeft.Lo64 > decRight.Lo64)
+ {
+ return 1;
+ }
+ return 0;
+ }
+
+ // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL
+ static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight)
+ {
+ static const ULONG powersOfTen[] =
+ {
+ 10ul,
+ 100ul,
+ 1000ul,
+ 10000ul,
+ 100000ul,
+ 1000000ul,
+ 10000000ul,
+ 100000000ul,
+ 1000000000ul
+ };
+ static const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]);
+ if (!pdecLeft || !pdecRight)
+ {
+ return VARCMP_NULL;
+ }
+
+ // Degenerate case - at least one comparand is of the form
+ // [+-]0*10^N (denormalized zero)
+ bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32);
+ bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32);
+ if (bLeftZero && bRightZero)
+ {
+ return VARCMP_EQ;
+ }
+ bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0);
+ bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0);
+ if (bLeftZero)
+ {
+ return (bRightNeg ? VARCMP_GT : VARCMP_LT);
+ }
+ // This also covers the case where the comparands have different signs
+ if (bRightZero || bLeftNeg != bRightNeg)
+ {
+ return (bLeftNeg ? VARCMP_LT : VARCMP_GT);
+ }
+
+ // Here both comparands have the same sign and need to be compared
+ // on mantissa and scale. The result is obvious when
+ // 1. Scales are equal (then compare mantissas)
+ // 2. A number with smaller scale is also the one with larger mantissa
+ // (then this number is obviously larger)
+ // In the remaining case, we would multiply the number with smaller
+ // scale by 10 and simultaneously increment its scale (which amounts to
+ // adding trailing zeros after decimal point), until the numbers fall under
+ // one of the two cases above
+ DECIMAL temp;
+ bool bInvert = bLeftNeg; // the final result needs to be inverted
+ if (pdecLeft->scale < pdecRight->scale)
+ {
+ temp = *pdecLeft;
+ }
+ else
+ {
+ temp = *pdecRight;
+ pdecRight = pdecLeft;
+ bInvert = !bInvert;
+ }
+
+ // Now temp is the number with smaller (or equal) scale, and
+ // we can modify it freely without touching original parameters
+ int comp;
+ while ((comp = CompareMantissas(temp, *pdecRight)) < 0 &&
+ temp.scale < pdecRight->scale)
+ {
+ // Multiply by an appropriate power of 10
+ int scaleDiff = pdecRight->scale - temp.scale;
+ if (scaleDiff > largestPower)
+ {
+ // Keep the multiplier representable in 32bit
+ scaleDiff = largestPower;
+ }
+ DWORDLONG power = powersOfTen[scaleDiff - 1];
+ // Multiply temp's mantissa by power
+ DWORDLONG product = temp.Lo32 * power;
+ ULONG carry = static_cast<ULONG>(product >> 32);
+ temp.Lo32 = static_cast<ULONG>(product);
+ product = temp.Mid32 * power + carry;
+ carry = static_cast<ULONG>(product >> 32);
+ temp.Mid32 = static_cast<ULONG>(product);
+ product = temp.Hi32 * power + carry;
+ if (static_cast<ULONG>(product >> 32))
+ {
+ // Multiplication overflowed - pdecLeft is clearly larger
+ break;
+ }
+ temp.Hi32 = static_cast<ULONG>(product);
+ temp.scale = (BYTE)(temp.scale + scaleDiff);
+ }
+ if (temp.scale < pdecRight->scale)
+ {
+ comp = 1;
+ }
+ if (bInvert)
+ {
+ comp = -comp;
+ }
+ return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ);
+ }
+
+ static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+ {
+ ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);
+
+ LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
+ LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
+ LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
+
+ int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue);
+ nRet--;
+ return pInfo->bDescending ? -nRet : nRet;
+ }
+#endif // !_WIN32_WCE
+
+ BEGIN_MSG_MAP(CSortListViewImpl)
+ MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn)
+ MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn)
+ NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick)
+ NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+ END_MSG_MAP()
+
+ LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
+ if(lRet == -1)
+ return -1;
+
+ WORD wType = 0;
+ m_arrColSortType.Add(wType);
+ int nCount = m_arrColSortType.GetSize();
+ ATLASSERT(nCount == GetColumnCount());
+
+ for(int i = nCount - 1; i > lRet; i--)
+ m_arrColSortType[i] = m_arrColSortType[i - 1];
+ m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT;
+
+ if(lRet <= m_iSortColumn)
+ m_iSortColumn++;
+
+ return lRet;
+ }
+
+ LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
+ if(lRet == 0)
+ return 0;
+
+ int iCol = (int)wParam;
+ if(m_iSortColumn == iCol)
+ m_iSortColumn = -1;
+ else if(m_iSortColumn > iCol)
+ m_iSortColumn--;
+ m_arrColSortType.RemoveAt(iCol);
+
+ return lRet;
+ }
+
+ LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ LPNMHEADER p = (LPNMHEADER)pnmh;
+ if(p->iButton == 0)
+ {
+ int iOld = m_iSortColumn;
+ bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false;
+ if(DoSortItems(p->iItem, bDescending))
+ NotifyParentSortChanged(p->iItem, iOld);
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifndef _WIN32_WCE
+ if(wParam == SPI_SETNONCLIENTMETRICS)
+ GetSystemSettings();
+#else // CE specific
+ wParam; // avoid level 4 warning
+ GetSystemSettings();
+#endif // _WIN32_WCE
+ bHandled = FALSE;
+ return 0;
+ }
+
+ void GetSystemSettings()
+ {
+ if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull())
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CreateSortBitmaps();
+ if(m_iSortColumn != -1)
+ SetSortColumn(m_iSortColumn);
+ }
+ }
+
+};
+
+
+typedef ATL::CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_SHOWSELALWAYS , WS_EX_CLIENTEDGE> CSortListViewCtrlTraits;
+
+template <class T, class TBase = CListViewCtrl, class TWinTraits = CSortListViewCtrlTraits>
+class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl<T, TBase, TWinTraits>, public CSortListViewImpl<T>
+{
+public:
+ DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
+
+ bool SortItems(int iCol, bool bDescending = false)
+ {
+ return DoSortItems(iCol, bDescending);
+ }
+
+ BEGIN_MSG_MAP(CSortListViewCtrlImpl)
+ MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl<T>::OnInsertColumn)
+ MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl<T>::OnDeleteColumn)
+ NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl<T>::OnHeaderItemClick)
+ NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl<T>::OnHeaderItemClick)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl<T>::OnSettingChange)
+ END_MSG_MAP()
+};
+
+class CSortListViewCtrl : public CSortListViewCtrlImpl<CSortListViewCtrl>
+{
+public:
+ DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName())
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTabView - implements tab view window
+
+// TabView Notifications
+#define TBVN_PAGEACTIVATED (0U-741)
+#define TBVN_CONTEXTMENU (0U-742)
+
+// Notification data for TBVN_CONTEXTMENU
+struct TBVCONTEXTMENUINFO
+{
+ NMHDR hdr;
+ POINT pt;
+};
+
+typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO;
+
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE)
+
+// Declarations and enums
+ struct TABVIEWPAGE
+ {
+ HWND hWnd;
+ LPTSTR lpstrTitle;
+ LPVOID pData;
+ };
+
+ struct TCITEMEXTRA
+ {
+ TCITEMHEADER tciheader;
+ TABVIEWPAGE tvpage;
+
+ operator LPTCITEM() { return (LPTCITEM)this; }
+ };
+
+ enum
+ {
+ m_nTabID = 1313,
+ m_cxMoveMark = 6,
+ m_cyMoveMark = 3,
+ m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1)
+ };
+
+// Data members
+ ATL::CContainedWindowT<CTabCtrl> m_tab;
+ int m_cyTabHeight;
+
+ int m_nActivePage;
+
+ int m_nInsertItem;
+ POINT m_ptStartDrag;
+
+ CMenuHandle m_menu;
+
+ int m_cchTabTextLength;
+
+ int m_nMenuItemsCount;
+
+ ATL::CWindow m_wndTitleBar;
+ LPTSTR m_lpstrTitleBarBase;
+ int m_cchTitleBarLength;
+
+ CImageList m_ilDrag;
+
+ bool m_bDestroyPageOnRemove:1;
+ bool m_bDestroyImageList:1;
+ bool m_bActivePageMenuItem:1;
+ bool m_bActiveAsDefaultMenuItem:1;
+ bool m_bEmptyMenuItem:1;
+ bool m_bWindowsMenuItem:1;
+ bool m_bNoTabDrag:1;
+ // internal
+ bool m_bTabCapture:1;
+ bool m_bTabDrag:1;
+ bool m_bInternalFont:1;
+
+// Constructor/destructor
+ CTabViewImpl() :
+ m_nActivePage(-1),
+ m_cyTabHeight(0),
+ m_tab(this, 1),
+ m_nInsertItem(-1),
+ m_cchTabTextLength(30),
+ m_nMenuItemsCount(10),
+ m_lpstrTitleBarBase(NULL),
+ m_cchTitleBarLength(100),
+ m_bDestroyPageOnRemove(true),
+ m_bDestroyImageList(true),
+ m_bActivePageMenuItem(true),
+ m_bActiveAsDefaultMenuItem(false),
+ m_bEmptyMenuItem(false),
+ m_bWindowsMenuItem(false),
+ m_bNoTabDrag(false),
+ m_bTabCapture(false),
+ m_bTabDrag(false),
+ m_bInternalFont(false)
+ {
+ m_ptStartDrag.x = 0;
+ m_ptStartDrag.y = 0;
+ }
+
+ ~CTabViewImpl()
+ {
+ delete [] m_lpstrTitleBarBase;
+ }
+
+// Message filter function - to be called from PreTranslateMessage of the main window
+ BOOL PreTranslateMessage(MSG* pMsg)
+ {
+ if(IsWindow() == FALSE)
+ return FALSE;
+
+ BOOL bRet = FALSE;
+
+ // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page)
+ int nCount = GetPageCount();
+ if(nCount > 0)
+ {
+ bool bControl = (::GetKeyState(VK_CONTROL) < 0);
+ if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl)
+ {
+ if(nCount > 1)
+ {
+ int nPage = m_nActivePage;
+ bool bShift = (::GetKeyState(VK_SHIFT) < 0);
+ if(bShift)
+ nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1);
+ else
+ nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0;
+
+ SetActivePage(nPage);
+ T* pT = static_cast<T*>(this);
+ pT->OnPageActivated(m_nActivePage);
+ }
+
+ bRet = TRUE;
+ }
+ }
+
+ // If we are doing drag-drop, check for Escape key that cancels it
+ if(bRet == FALSE)
+ {
+ if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)
+ {
+ ::ReleaseCapture();
+ bRet = TRUE;
+ }
+ }
+
+ // Pass the message to the active page
+ if(bRet == FALSE)
+ {
+ if(m_nActivePage != -1)
+ bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg);
+ }
+
+ return bRet;
+ }
+
+// Attributes
+ int GetPageCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_tab.GetItemCount();
+ }
+
+ int GetActivePage() const
+ {
+ return m_nActivePage;
+ }
+
+ void SetActivePage(int nPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ T* pT = static_cast<T*>(this);
+
+ SetRedraw(FALSE);
+
+ if(m_nActivePage != -1)
+ ::ShowWindow(GetPageHWND(m_nActivePage), FALSE);
+ m_nActivePage = nPage;
+ m_tab.SetCurSel(m_nActivePage);
+ ::ShowWindow(GetPageHWND(m_nActivePage), TRUE);
+
+ pT->UpdateLayout();
+
+ SetRedraw(TRUE);
+ RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+
+ if(::GetFocus() != m_tab.m_hWnd)
+ ::SetFocus(GetPageHWND(m_nActivePage));
+
+ pT->UpdateTitleBar();
+ pT->UpdateMenu();
+ }
+
+ HIMAGELIST GetImageList() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_tab.GetImageList();
+ }
+
+ HIMAGELIST SetImageList(HIMAGELIST hImageList)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return m_tab.SetImageList(hImageList);
+ }
+
+ void SetWindowMenu(HMENU hMenu)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ m_menu = hMenu;
+
+ T* pT = static_cast<T*>(this);
+ pT->UpdateMenu();
+ }
+
+ void SetTitleBarWindow(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ delete [] m_lpstrTitleBarBase;
+ m_lpstrTitleBarBase = NULL;
+
+ m_wndTitleBar = hWnd;
+ if(hWnd == NULL)
+ return;
+
+ int cchLen = m_wndTitleBar.GetWindowTextLength() + 1;
+ ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]);
+ if(m_lpstrTitleBarBase != NULL)
+ {
+ m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen);
+ T* pT = static_cast<T*>(this);
+ pT->UpdateTitleBar();
+ }
+ }
+
+// Page attributes
+ HWND GetPageHWND(int nPage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_PARAM;
+ m_tab.GetItem(nPage, tcix);
+
+ return tcix.tvpage.hWnd;
+ }
+
+ LPCTSTR GetPageTitle(int nPage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_PARAM;
+ if(m_tab.GetItem(nPage, tcix) == FALSE)
+ return NULL;
+
+ return tcix.tvpage.lpstrTitle;
+ }
+
+ bool SetPageTitle(int nPage, LPCTSTR lpstrTitle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ T* pT = static_cast<T*>(this);
+
+ int cchBuff = lstrlen(lpstrTitle) + 1;
+ LPTSTR lpstrBuff = NULL;
+ ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
+ if(lpstrBuff == NULL)
+ return false;
+
+ SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_PARAM;
+ if(m_tab.GetItem(nPage, tcix) == FALSE)
+ return false;
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
+ if(lpstrTabText == NULL)
+ return false;
+
+ delete [] tcix.tvpage.lpstrTitle;
+
+ pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
+
+ tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM;
+ tcix.tciheader.pszText = lpstrTabText;
+ tcix.tvpage.lpstrTitle = lpstrBuff;
+ if(m_tab.SetItem(nPage, tcix) == FALSE)
+ return false;
+
+ pT->UpdateTitleBar();
+ pT->UpdateMenu();
+
+ return true;
+ }
+
+ LPVOID GetPageData(int nPage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_PARAM;
+ m_tab.GetItem(nPage, tcix);
+
+ return tcix.tvpage.pData;
+ }
+
+ LPVOID SetPageData(int nPage, LPVOID pData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_PARAM;
+ m_tab.GetItem(nPage, tcix);
+ LPVOID pDataOld = tcix.tvpage.pData;
+
+ tcix.tvpage.pData = pData;
+ m_tab.SetItem(nPage, tcix);
+
+ return pDataOld;
+ }
+
+ int GetPageImage(int nPage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_IMAGE;
+ m_tab.GetItem(nPage, tcix);
+
+ return tcix.tciheader.iImage;
+ }
+
+ int SetPageImage(int nPage, int nImage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_IMAGE;
+ m_tab.GetItem(nPage, tcix);
+ int nImageOld = tcix.tciheader.iImage;
+
+ tcix.tciheader.iImage = nImage;
+ m_tab.SetItem(nPage, tcix);
+
+ return nImageOld;
+ }
+
+// Operations
+ bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
+ {
+ return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData);
+ }
+
+ bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage));
+
+ T* pT = static_cast<T*>(this);
+
+ int cchBuff = lstrlen(lpstrTitle) + 1;
+ LPTSTR lpstrBuff = NULL;
+ ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
+ if(lpstrBuff == NULL)
+ return false;
+
+ SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
+ if(lpstrTabText == NULL)
+ return false;
+
+ pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
+
+ SetRedraw(FALSE);
+
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ tcix.tciheader.pszText = lpstrTabText;
+ tcix.tciheader.iImage = nImage;
+ tcix.tvpage.hWnd = hWndView;
+ tcix.tvpage.lpstrTitle = lpstrBuff;
+ tcix.tvpage.pData = pData;
+ int nItem = m_tab.InsertItem(nPage, tcix);
+ if(nItem == -1)
+ {
+ delete [] lpstrBuff;
+ SetRedraw(TRUE);
+ return false;
+ }
+
+ SetActivePage(nItem);
+ pT->OnPageActivated(m_nActivePage);
+
+ if(GetPageCount() == 1)
+ pT->ShowTabControl(true);
+
+ pT->UpdateLayout();
+
+ SetRedraw(TRUE);
+ RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+
+ return true;
+ }
+
+ void RemovePage(int nPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(IsValidPageIndex(nPage));
+
+ T* pT = static_cast<T*>(this);
+
+ SetRedraw(FALSE);
+
+ if(GetPageCount() == 1)
+ pT->ShowTabControl(false);
+
+ if(m_bDestroyPageOnRemove)
+ ::DestroyWindow(GetPageHWND(nPage));
+ else
+ ::ShowWindow(GetPageHWND(nPage), FALSE);
+ LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage);
+ delete [] lpstrTitle;
+
+ ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE);
+
+ if(m_nActivePage == nPage)
+ {
+ m_nActivePage = -1;
+
+ if(nPage > 0)
+ {
+ SetActivePage(nPage - 1);
+ }
+ else if(GetPageCount() > 0)
+ {
+ SetActivePage(nPage);
+ }
+ else
+ {
+ SetRedraw(TRUE);
+ Invalidate();
+ UpdateWindow();
+ pT->UpdateTitleBar();
+ pT->UpdateMenu();
+ }
+ }
+ else
+ {
+ nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage;
+ m_nActivePage = -1;
+ SetActivePage(nPage);
+ }
+
+ pT->OnPageActivated(m_nActivePage);
+ }
+
+ void RemoveAllPages()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ if(GetPageCount() == 0)
+ return;
+
+ T* pT = static_cast<T*>(this);
+
+ SetRedraw(FALSE);
+
+ pT->ShowTabControl(false);
+
+ for(int i = 0; i < GetPageCount(); i++)
+ {
+ if(m_bDestroyPageOnRemove)
+ ::DestroyWindow(GetPageHWND(i));
+ else
+ ::ShowWindow(GetPageHWND(i), FALSE);
+ LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i);
+ delete [] lpstrTitle;
+ }
+ m_tab.DeleteAllItems();
+
+ m_nActivePage = -1;
+ pT->OnPageActivated(m_nActivePage);
+
+ SetRedraw(TRUE);
+ Invalidate();
+ UpdateWindow();
+
+ pT->UpdateTitleBar();
+ pT->UpdateMenu();
+ }
+
+ int PageIndexFromHwnd(HWND hWnd) const
+ {
+ int nIndex = -1;
+
+ for(int i = 0; i < GetPageCount(); i++)
+ {
+ if(GetPageHWND(i) == hWnd)
+ {
+ nIndex = i;
+ break;
+ }
+ }
+
+ return nIndex;
+ }
+
+ void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ CMenuHandle menu = hMenu;
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ int nFirstPos = 0;
+
+ // Find first menu item in our range
+#ifndef _WIN32_WCE
+ for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++)
+ {
+ UINT nID = menu.GetMenuItemID(nFirstPos);
+ if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST)
+ break;
+ }
+#else // CE specific
+ for(nFirstPos = 0; ; nFirstPos++)
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_ID;
+ BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii);
+ if(bRet == FALSE)
+ break;
+ if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST)
+ break;
+ }
+#endif // _WIN32_WCE
+
+ // Remove all menu items for tab pages
+ BOOL bRet = TRUE;
+ while(bRet != FALSE)
+ bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION);
+
+ // Add separator if it's not already there
+ int nPageCount = GetPageCount();
+ if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0))
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_TYPE;
+ menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
+ if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0))
+ {
+ menu.AppendMenu(MF_SEPARATOR);
+ nFirstPos++;
+ }
+ }
+
+ // Add menu items for all pages
+ if(nPageCount > 0)
+ {
+ // Append menu items for all pages
+ const int cchPrefix = 3; // 2 digits + space
+ nMenuItemsCount = min(min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax);
+ ATLASSERT(nMenuItemsCount < 100); // 2 digits only
+ if(nMenuItemsCount >= 100)
+ nMenuItemsCount = 99;
+
+ for(int i = 0; i < nMenuItemsCount; i++)
+ {
+ LPCTSTR lpstrTitle = GetPageTitle(i);
+ int nLen = lstrlen(lpstrTitle);
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1);
+ ATLASSERT(lpstrText != NULL);
+ if(lpstrText != NULL)
+ {
+ LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s");
+ SecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle);
+ menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText);
+ }
+ }
+
+ // Mark active page
+ if(bActivePageMenuItem && (m_nActivePage != -1))
+ {
+#ifndef _WIN32_WCE
+ if(bActiveAsDefaultMenuItem)
+ {
+ menu.SetMenuDefaultItem((UINT)-1, TRUE);
+ menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE);
+ }
+ else
+#else // CE specific
+ bActiveAsDefaultMenuItem; // avoid level 4 warning
+#endif // _WIN32_WCE
+ {
+ menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION);
+ }
+ }
+ }
+ else
+ {
+ if(bEmptyMenuItem)
+ {
+ menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText());
+ menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED);
+ }
+
+ // Remove separator if nothing else is there
+ if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0))
+ {
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_TYPE;
+ menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
+ if((mii.fType & MFT_SEPARATOR) != 0)
+ menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION);
+ }
+ }
+
+ // Add "Windows..." menu item
+ if(bWindowsMenuItem)
+ menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText());
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CTabViewImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
+ MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
+ NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged)
+ NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification)
+#ifndef _WIN32_WCE
+ NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo)
+#endif // !_WIN32_WCE
+ FORWARD_NOTIFICATIONS()
+ ALT_MSG_MAP(1) // tab control
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove)
+ MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp)
+ MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->CreateTabControl();
+
+ return 0;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ RemoveAllPages();
+
+ if(m_bDestroyImageList)
+ {
+ CImageList il = m_tab.SetImageList(NULL);
+ if(il.m_hImageList != NULL)
+ il.Destroy();
+ }
+
+ if(m_bInternalFont)
+ {
+ HFONT hFont = m_tab.GetFont();
+ m_tab.SetFont(NULL, FALSE);
+ ::DeleteObject(hFont);
+ m_bInternalFont = false;
+ }
+
+ return 0;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ return 0;
+ }
+
+ LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_nActivePage != -1)
+ ::SetFocus(GetPageHWND(m_nActivePage));
+ return 0;
+ }
+
+ LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return m_tab.SendMessage(WM_GETFONT);
+ }
+
+ LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(m_bInternalFont)
+ {
+ HFONT hFont = m_tab.GetFont();
+ m_tab.SetFont(NULL, FALSE);
+ ::DeleteObject(hFont);
+ m_bInternalFont = false;
+ }
+
+ m_tab.SendMessage(WM_SETFONT, wParam, lParam);
+
+ T* pT = static_cast<T*>(this);
+ m_cyTabHeight = pT->CalcTabHeight();
+
+ if((BOOL)lParam != FALSE)
+ pT->UpdateLayout();
+
+ return 0;
+ }
+
+ LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
+ {
+ SetActivePage(m_tab.GetCurSel());
+ T* pT = static_cast<T*>(this);
+ pT->OnPageActivated(m_nActivePage);
+
+ return 0;
+ }
+
+ LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
+ {
+ // nothing to do - this just blocks all tab control
+ // notifications from being propagated further
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh;
+ if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips())
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateTooltipText(pTTDI);
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+
+ return 0;
+ }
+#endif // !_WIN32_WCE
+
+// Tab control message handlers
+ LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(!m_bNoTabDrag && (m_tab.GetItemCount() > 1))
+ {
+ m_bTabCapture = true;
+ m_tab.SetCapture();
+
+ m_ptStartDrag.x = GET_X_LPARAM(lParam);
+ m_ptStartDrag.y = GET_Y_LPARAM(lParam);
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(m_bTabCapture)
+ {
+ if(m_bTabDrag)
+ {
+ TCHITTESTINFO hti = { 0 };
+ hti.pt.x = GET_X_LPARAM(lParam);
+ hti.pt.y = GET_Y_LPARAM(lParam);
+ int nItem = m_tab.HitTest(&hti);
+ if(nItem != -1)
+ MovePage(m_nActivePage, nItem);
+ }
+
+ ::ReleaseCapture();
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_bTabCapture)
+ {
+ m_bTabCapture = false;
+
+ if(m_bTabDrag)
+ {
+ m_bTabDrag = false;
+ T* pT = static_cast<T*>(this);
+ pT->DrawMoveMark(-1);
+
+#ifndef _WIN32_WCE
+ m_ilDrag.DragLeave(GetDesktopWindow());
+#endif // !_WIN32_WCE
+ m_ilDrag.EndDrag();
+
+ m_ilDrag.Destroy();
+ m_ilDrag.m_hImageList = NULL;
+ }
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+
+ if(m_bTabCapture)
+ {
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+
+ if(!m_bTabDrag)
+ {
+#ifndef _WIN32_WCE
+ if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) ||
+ abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG))
+#else // CE specific
+ if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 ||
+ abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4)
+#endif // _WIN32_WCE
+ {
+ T* pT = static_cast<T*>(this);
+ pT->GenerateDragImage(m_nActivePage);
+
+ int cxCursor = ::GetSystemMetrics(SM_CXCURSOR);
+ int cyCursor = ::GetSystemMetrics(SM_CYCURSOR);
+ m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2));
+#ifndef _WIN32_WCE
+ POINT ptEnter = m_ptStartDrag;
+ m_tab.ClientToScreen(&ptEnter);
+ m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter);
+#endif // !_WIN32_WCE
+
+ m_bTabDrag = true;
+ }
+ }
+
+ if(m_bTabDrag)
+ {
+ TCHITTESTINFO hti = { 0 };
+ hti.pt = pt;
+ int nItem = m_tab.HitTest(&hti);
+
+ T* pT = static_cast<T*>(this);
+ pT->SetMoveCursor(nItem != -1);
+
+ if(m_nInsertItem != nItem)
+ pT->DrawMoveMark(nItem);
+
+ m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE);
+ m_tab.ClientToScreen(&pt);
+ m_ilDrag.DragMove(pt);
+
+ bHandled = TRUE;
+ }
+ }
+
+ return 0;
+ }
+
+ LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ TCHITTESTINFO hti = { 0 };
+ hti.pt.x = GET_X_LPARAM(lParam);
+ hti.pt.y = GET_Y_LPARAM(lParam);
+ int nItem = m_tab.HitTest(&hti);
+ if(nItem != -1)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->OnContextMenu(nItem, hti.pt);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bool bShift = (::GetKeyState(VK_SHIFT) < 0);
+ if(wParam == VK_F10 && bShift)
+ {
+ if(m_nActivePage != -1)
+ {
+ RECT rect = { 0 };
+ m_tab.GetItemRect(m_nActivePage, &rect);
+ POINT pt = { rect.left, rect.bottom };
+ T* pT = static_cast<T*>(this);
+ pT->OnContextMenu(m_nActivePage, pt);
+ }
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+
+ return 0;
+ }
+
+// Implementation helpers
+ bool IsValidPageIndex(int nPage) const
+ {
+ return (nPage >= 0 && nPage < GetPageCount());
+ }
+
+ bool MovePage(int nMovePage, int nInsertBeforePage)
+ {
+ ATLASSERT(IsValidPageIndex(nMovePage));
+ ATLASSERT(IsValidPageIndex(nInsertBeforePage));
+
+ if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage))
+ return false;
+
+ if(nMovePage == nInsertBeforePage)
+ return true; // nothing to do
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
+ if(lpstrTabText == NULL)
+ return false;
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ tcix.tciheader.pszText = lpstrTabText;
+ tcix.tciheader.cchTextMax = m_cchTabTextLength + 1;
+ BOOL bRet = m_tab.GetItem(nMovePage, tcix);
+ ATLASSERT(bRet != FALSE);
+ if(bRet == FALSE)
+ return false;
+
+ int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage;
+ int nNewItem = m_tab.InsertItem(nInsertItem, tcix);
+ ATLASSERT(nNewItem == nInsertItem);
+ if(nNewItem != nInsertItem)
+ {
+ ATLVERIFY(m_tab.DeleteItem(nNewItem));
+ return false;
+ }
+
+ if(nMovePage > nInsertBeforePage)
+ ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE);
+ else if(nMovePage < nInsertBeforePage)
+ ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE);
+
+ SetActivePage(nInsertBeforePage);
+ T* pT = static_cast<T*>(this);
+ pT->OnPageActivated(m_nActivePage);
+
+ return true;
+ }
+
+// Implementation overrideables
+ bool CreateTabControl()
+ {
+#ifndef _WIN32_WCE
+ m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID);
+#else // CE specific
+ m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID);
+#endif // _WIN32_WCE
+ ATLASSERT(m_tab.m_hWnd != NULL);
+ if(m_tab.m_hWnd == NULL)
+ return false;
+
+ m_tab.SetFont(AtlCreateControlFont());
+ m_bInternalFont = true;
+
+ m_tab.SetItemExtra(sizeof(TABVIEWPAGE));
+
+ T* pT = static_cast<T*>(this);
+ m_cyTabHeight = pT->CalcTabHeight();
+
+ return true;
+ }
+
+ int CalcTabHeight()
+ {
+ int nCount = m_tab.GetItemCount();
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_TEXT;
+ tcix.tciheader.pszText = _T("NS");
+ int nIndex = m_tab.InsertItem(nCount, tcix);
+
+ RECT rect = { 0, 0, 1000, 1000 };
+ m_tab.AdjustRect(FALSE, &rect);
+
+ RECT rcWnd = { 0, 0, 1000, rect.top };
+ ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle());
+
+ int nHeight = rcWnd.bottom - rcWnd.top;
+
+ m_tab.DeleteItem(nIndex);
+
+ return nHeight;
+ }
+
+ void ShowTabControl(bool bShow)
+ {
+ m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE);
+ }
+
+ void UpdateLayout()
+ {
+ RECT rect;
+ GetClientRect(&rect);
+
+ if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
+ m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER);
+
+ if(m_nActivePage != -1)
+ ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, m_cyTabHeight, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_NOZORDER);
+ }
+
+ void UpdateMenu()
+ {
+ if(m_menu.m_hMenu != NULL)
+ BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem);
+ }
+
+ void UpdateTitleBar()
+ {
+ if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL)
+ return; // nothing to do
+
+ if(m_nActivePage != -1)
+ {
+ T* pT = static_cast<T*>(this);
+ LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage);
+ LPCTSTR lpstrDivider = pT->GetTitleDividerText();
+ int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1;
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer);
+ ATLASSERT(lpstrPageTitle != NULL);
+ if(lpstrPageTitle != NULL)
+ {
+ pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1);
+ SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider);
+ SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase);
+ }
+ else
+ {
+ lpstrPageTitle = m_lpstrTitleBarBase;
+ }
+
+ m_wndTitleBar.SetWindowText(lpstrPageTitle);
+ }
+ else
+ {
+ m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase);
+ }
+ }
+
+ void DrawMoveMark(int nItem)
+ {
+ T* pT = static_cast<T*>(this);
+
+ if(m_nInsertItem != -1)
+ {
+ RECT rect = { 0 };
+ pT->GetMoveMarkRect(rect);
+ m_tab.InvalidateRect(&rect);
+ }
+
+ m_nInsertItem = nItem;
+
+ if(m_nInsertItem != -1)
+ {
+ CClientDC dc(m_tab.m_hWnd);
+
+ RECT rect = { 0 };
+ pT->GetMoveMarkRect(rect);
+
+ CPen pen;
+ pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT));
+ CBrush brush;
+ brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT));
+
+ HPEN hPenOld = dc.SelectPen(pen);
+ HBRUSH hBrushOld = dc.SelectBrush(brush);
+
+ int x = rect.left;
+ int y = rect.top;
+ POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } };
+ dc.Polygon(ptsTop, 3);
+
+ y = rect.bottom - 1;
+ POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } };
+ dc.Polygon(ptsBottom, 3);
+
+ dc.SelectPen(hPenOld);
+ dc.SelectBrush(hBrushOld);
+ }
+ }
+
+ void GetMoveMarkRect(RECT& rect) const
+ {
+ m_tab.GetClientRect(&rect);
+
+ RECT rcItem = { 0 };
+ m_tab.GetItemRect(m_nInsertItem, &rcItem);
+
+ if(m_nInsertItem <= m_nActivePage)
+ {
+ rect.left = rcItem.left - m_cxMoveMark / 2 - 1;
+ rect.right = rcItem.left + m_cxMoveMark / 2;
+ }
+ else
+ {
+ rect.left = rcItem.right - m_cxMoveMark / 2 - 1;
+ rect.right = rcItem.right + m_cxMoveMark / 2;
+ }
+ }
+
+ void SetMoveCursor(bool bCanMove)
+ {
+ ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO));
+ }
+
+ void GenerateDragImage(int nItem)
+ {
+ ATLASSERT(IsValidPageIndex(nItem));
+
+#ifndef _WIN32_WCE
+ RECT rcItem = { 0 };
+ m_tab.GetItemRect(nItem, &rcItem);
+ ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item
+#else // CE specific
+ nItem; // avoid level 4 warning
+ RECT rcItem = { 0, 0, 40, 20 };
+#endif // _WIN32_WCE
+
+ ATLASSERT(m_ilDrag.m_hImageList == NULL);
+ m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1);
+
+ CClientDC dc(m_hWnd);
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(dc);
+ ATLASSERT(dcMem.m_hDC != NULL);
+ dcMem.SetViewportOrg(-rcItem.left, -rcItem.top);
+
+ CBitmap bmp;
+ bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top);
+ ATLASSERT(bmp.m_hBitmap != NULL);
+
+ HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);
+#ifndef _WIN32_WCE
+ m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC);
+#else // CE specific
+ dcMem.Rectangle(&rcItem);
+#endif // _WIN32_WCE
+ dcMem.SelectBitmap(hBmpOld);
+
+ ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1);
+ }
+
+ void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle)
+ {
+ if(lstrlen(lpstrTitle) >= cchShortTitle)
+ {
+ LPCTSTR lpstrEllipsis = _T("...");
+ int cchEllipsis = lstrlen(lpstrEllipsis);
+ SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1);
+ SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis);
+ }
+ else
+ {
+ SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle);
+ }
+ }
+
+#ifndef _WIN32_WCE
+ void UpdateTooltipText(LPNMTTDISPINFO pTTDI)
+ {
+ ATLASSERT(pTTDI != NULL);
+ pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom);
+ }
+#endif // !_WIN32_WCE
+
+// Text for menu items and title bar - override to provide different strings
+ static LPCTSTR GetEmptyListText()
+ {
+ return _T("(Empty)");
+ }
+
+ static LPCTSTR GetWindowsMenuItemText()
+ {
+ return _T("&Windows...");
+ }
+
+ static LPCTSTR GetTitleDividerText()
+ {
+ return _T(" - ");
+ }
+
+// Notifications - override to provide different behavior
+ void OnPageActivated(int nPage)
+ {
+ NMHDR nmhdr = { 0 };
+ nmhdr.hwndFrom = m_hWnd;
+ nmhdr.idFrom = nPage;
+ nmhdr.code = TBVN_PAGEACTIVATED;
+ ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);
+ }
+
+ void OnContextMenu(int nPage, POINT pt)
+ {
+ m_tab.ClientToScreen(&pt);
+
+ TBVCONTEXTMENUINFO cmi = { 0 };
+ cmi.hdr.hwndFrom = m_hWnd;
+ cmi.hdr.idFrom = nPage;
+ cmi.hdr.code = TBVN_CONTEXTMENU;
+ cmi.pt = pt;
+ ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi);
+ }
+};
+
+class CTabView : public CTabViewImpl<CTabView>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE)
+};
+
+}; // namespace WTL
+
+#endif // __ATLCTRLX_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLDDX_H__
+#define __ATLDDX_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlddx.h requires atlapp.h to be included first
+#endif
+
+#if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
+ #error Cannot use floating point DDX with _ATL_MIN_CRT defined
+#endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
+
+#ifdef _ATL_USE_DDX_FLOAT
+ #include <float.h>
+#endif // _ATL_USE_DDX_FLOAT
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CWinDataExchange<T>
+
+
+namespace WTL
+{
+
+// Constants
+#define DDX_LOAD FALSE
+#define DDX_SAVE TRUE
+
+// DDX map macros
+#define BEGIN_DDX_MAP(thisClass) \
+ BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \
+ { \
+ bSaveAndValidate; \
+ nCtlID;
+
+#define DDX_TEXT(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
+ return FALSE; \
+ }
+
+#define DDX_TEXT_LEN(nID, var, len) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
+ return FALSE; \
+ }
+
+#define DDX_INT(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \
+ return FALSE; \
+ }
+
+#define DDX_INT_RANGE(nID, var, min, max) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \
+ return FALSE; \
+ }
+
+#define DDX_UINT(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \
+ return FALSE; \
+ }
+
+#define DDX_UINT_RANGE(nID, var, min, max) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \
+ return FALSE; \
+ }
+
+#ifdef _ATL_USE_DDX_FLOAT
+#define DDX_FLOAT(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Float(nID, var, bSaveAndValidate)) \
+ return FALSE; \
+ }
+
+#define DDX_FLOAT_RANGE(nID, var, min, max) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \
+ return FALSE; \
+ }
+#define DDX_FLOAT_P(nID, var, precision) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \
+ return FALSE; \
+ }
+
+#define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ { \
+ if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \
+ return FALSE; \
+ }
+#endif // _ATL_USE_DDX_FLOAT
+
+#define DDX_CONTROL(nID, obj) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ DDX_Control(nID, obj, bSaveAndValidate);
+
+#define DDX_CONTROL_HANDLE(nID, obj) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ DDX_Control_Handle(nID, obj, bSaveAndValidate);
+
+#define DDX_CHECK(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ DDX_Check(nID, var, bSaveAndValidate);
+
+#define DDX_RADIO(nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ DDX_Radio(nID, var, bSaveAndValidate);
+
+#define END_DDX_MAP() \
+ return TRUE; \
+ }
+
+// DDX support for Tab, Combo, ListBox and ListView selection index
+// Note: Specialized versions require atlctrls.h to be included first
+#define DDX_INDEX(CtrlClass, nID, var) \
+ if(nCtlID == (UINT)-1 || nCtlID == nID) \
+ DDX_Index<CtrlClass>(nID, var, bSaveAndValidate);
+
+#ifdef __ATLCTRLS_H__
+ #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var)
+ #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var)
+ #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var)
+ #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var)
+#endif // __ATLCTRLS_H__
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWinDataExchange - provides support for DDX
+
+template <class T>
+class CWinDataExchange
+{
+public:
+// Data exchange method - override in your derived class
+ BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
+ {
+ // this one should never be called, override it in
+ // your derived class by implementing DDX map
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+// Helpers for validation error reporting
+ enum _XDataType
+ {
+ ddxDataNull = 0,
+ ddxDataText = 1,
+ ddxDataInt = 2,
+ ddxDataFloat = 3,
+ ddxDataDouble = 4
+ };
+
+ struct _XTextData
+ {
+ int nLength;
+ int nMaxLength;
+ };
+
+ struct _XIntData
+ {
+ long nVal;
+ long nMin;
+ long nMax;
+ };
+
+ struct _XFloatData
+ {
+ double nVal;
+ double nMin;
+ double nMax;
+ };
+
+ struct _XData
+ {
+ _XDataType nDataType;
+ union
+ {
+ _XTextData textData;
+ _XIntData intData;
+ _XFloatData floatData;
+ };
+ };
+
+// Text exchange
+ BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+
+ if(bSave)
+ {
+ HWND hWndCtrl = pT->GetDlgItem(nID);
+ int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR));
+ if(nRetLen < ::GetWindowTextLength(hWndCtrl))
+ bSuccess = FALSE;
+ }
+ else
+ {
+ ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
+ bSuccess = pT->SetDlgItemText(nID, lpstrText);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nLength > 0);
+ if(lstrlen(lpstrText) > nLength)
+ {
+ _XData data = { ddxDataText };
+ data.textData.nLength = lstrlen(lpstrText);
+ data.textData.nMaxLength = nLength;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+
+ BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+
+ if(bSave)
+ {
+ bSuccess = pT->GetDlgItemText(nID, bstrText);
+ }
+ else
+ {
+ USES_CONVERSION;
+ LPTSTR lpstrText = OLE2T(bstrText);
+ ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
+ bSuccess = pT->SetDlgItemText(nID, lpstrText);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nLength > 0);
+ if((int)::SysStringLen(bstrText) > nLength)
+ {
+ _XData data = { ddxDataText };
+ data.textData.nLength = (int)::SysStringLen(bstrText);
+ data.textData.nMaxLength = nLength;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+
+ BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+
+ if(bSave)
+ {
+ bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);
+ }
+ else
+ {
+ USES_CONVERSION;
+ LPTSTR lpstrText = OLE2T(bstrText);
+ ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
+ bSuccess = pT->SetDlgItemText(nID, lpstrText);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nLength > 0);
+ if((int)bstrText.Length() > nLength)
+ {
+ _XData data = { ddxDataText };
+ data.textData.nLength = (int)bstrText.Length();
+ data.textData.nMaxLength = nLength;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+
+ if(bSave)
+ {
+ HWND hWndCtrl = pT->GetDlgItem(nID);
+ int nLen = ::GetWindowTextLength(hWndCtrl);
+ int nRetLen = -1;
+ LPTSTR lpstr = strText.GetBufferSetLength(nLen);
+ if(lpstr != NULL)
+ {
+ nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1);
+ strText.ReleaseBuffer();
+ }
+ if(nRetLen < nLen)
+ bSuccess = FALSE;
+ }
+ else
+ {
+ bSuccess = pT->SetDlgItemText(nID, strText);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nLength > 0);
+ if(strText.GetLength() > nLength)
+ {
+ _XData data = { ddxDataText };
+ data.textData.nLength = strText.GetLength();
+ data.textData.nMaxLength = nLength;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+// Numeric exchange
+ template <class Type>
+ BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+
+ if(bSave)
+ {
+ nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);
+ }
+ else
+ {
+ ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
+ bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nMin != nMax);
+ if(nVal < nMin || nVal > nMax)
+ {
+ _XData data = { ddxDataInt };
+ data.intData.nVal = (long)nVal;
+ data.intData.nMin = (long)nMin;
+ data.intData.nMax = (long)nMax;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+
+// Float exchange
+#ifdef _ATL_USE_DDX_FLOAT
+ static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)
+ {
+ ATLASSERT(lpszText != NULL);
+ while (*lpszText == _T(' ') || *lpszText == _T('\t'))
+ lpszText++;
+
+ TCHAR chFirst = lpszText[0];
+ d = _tcstod(lpszText, (LPTSTR*)&lpszText);
+ if (d == 0.0 && chFirst != _T('0'))
+ return FALSE; // could not convert
+ while (*lpszText == _T(' ') || *lpszText == _T('\t'))
+ lpszText++;
+
+ if (*lpszText != _T('\0'))
+ return FALSE; // not terminated properly
+
+ return TRUE;
+ }
+
+ BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+ const int cchBuff = 32;
+ TCHAR szBuff[cchBuff] = { 0 };
+
+ if(bSave)
+ {
+ pT->GetDlgItemText(nID, szBuff, cchBuff);
+ double d = 0;
+ if(_AtlSimpleFloatParse(szBuff, d))
+ nVal = (float)d;
+ else
+ bSuccess = FALSE;
+ }
+ else
+ {
+ ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
+ SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
+ bSuccess = pT->SetDlgItemText(nID, szBuff);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nMin != nMax);
+ if(nVal < nMin || nVal > nMax)
+ {
+ _XData data = { ddxDataFloat };
+ data.floatData.nVal = (double)nVal;
+ data.floatData.nMin = (double)nMin;
+ data.floatData.nMax = (double)nMax;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+
+ BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bSuccess = TRUE;
+ const int cchBuff = 32;
+ TCHAR szBuff[cchBuff] = { 0 };
+
+ if(bSave)
+ {
+ pT->GetDlgItemText(nID, szBuff, cchBuff);
+ double d = 0;
+ if(_AtlSimpleFloatParse(szBuff, d))
+ nVal = d;
+ else
+ bSuccess = FALSE;
+ }
+ else
+ {
+ ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
+ SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
+ bSuccess = pT->SetDlgItemText(nID, szBuff);
+ }
+
+ if(!bSuccess)
+ {
+ pT->OnDataExchangeError(nID, bSave);
+ }
+ else if(bSave && bValidate) // validation
+ {
+ ATLASSERT(nMin != nMax);
+ if(nVal < nMin || nVal > nMax)
+ {
+ _XData data = { ddxDataFloat };
+ data.floatData.nVal = nVal;
+ data.floatData.nMin = nMin;
+ data.floatData.nMax = nMax;
+ pT->OnDataValidateError(nID, bSave, data);
+ bSuccess = FALSE;
+ }
+ }
+ return bSuccess;
+ }
+#endif // _ATL_USE_DDX_FLOAT
+
+// Full control subclassing (for CWindowImpl derived controls)
+ template <class TControl>
+ void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
+ {
+ if(!bSave && ctrl.m_hWnd == NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ ctrl.SubclassWindow(pT->GetDlgItem(nID));
+ }
+ }
+
+// Simple control attaching (for HWND wrapper controls)
+ template <class TControl>
+ void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)
+ {
+ if(!bSave && ctrl.m_hWnd == NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ ctrl = pT->GetDlgItem(nID);
+ }
+ }
+
+// Control state
+ void DDX_Check(UINT nID, int& nValue, BOOL bSave)
+ {
+ T* pT = static_cast<T*>(this);
+ HWND hWndCtrl = pT->GetDlgItem(nID);
+ if(bSave)
+ {
+ nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
+ ATLASSERT(nValue >= 0 && nValue <= 2);
+ }
+ else
+ {
+ if(nValue < 0 || nValue > 2)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue);
+ nValue = 0; // default to off
+ }
+ ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);
+ }
+ }
+
+ // variant that supports bool (checked/not-checked, no intermediate state)
+ void DDX_Check(UINT nID, bool& bCheck, BOOL bSave)
+ {
+ int nValue = bCheck ? 1 : 0;
+ DDX_Check(nID, nValue, bSave);
+
+ if(bSave)
+ {
+ if(nValue == 2)
+ ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue);
+ bCheck = (nValue == 1);
+ }
+ }
+
+ void DDX_Radio(UINT nID, int& nValue, BOOL bSave)
+ {
+ T* pT = static_cast<T*>(this);
+ HWND hWndCtrl = pT->GetDlgItem(nID);
+ ATLASSERT(hWndCtrl != NULL);
+
+ // must be first in a group of auto radio buttons
+ ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
+ ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
+
+ if(bSave)
+ nValue = -1; // value if none found
+
+ // walk all children in group
+ int nButton = 0;
+ do
+ {
+ if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
+ {
+ // control in group is a radio button
+ if(bSave)
+ {
+ if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
+ {
+ ATLASSERT(nValue == -1); // only set once
+ nValue = nButton;
+ }
+ }
+ else
+ {
+ // select button
+ ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);
+ }
+ nButton++;
+ }
+ else
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n"));
+ }
+ hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
+ }
+ while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
+ }
+
+// DDX support for Tab, Combo, ListBox and ListView selection index
+ template <class TCtrl>
+ INT _getSel(TCtrl& tCtrl)
+ {
+ return tCtrl.GetCurSel();
+ }
+
+ template <class TCtrl>
+ void _setSel(TCtrl& tCtrl, INT iSel)
+ {
+ if(iSel < 0)
+ tCtrl.SetCurSel(-1);
+ else
+ tCtrl.SetCurSel(iSel);
+ }
+
+#ifdef __ATLCTRLS_H__
+ // ListViewCtrl specialization
+ template <>
+ INT _getSel(WTL::CListViewCtrl& tCtrl)
+ {
+ return tCtrl.GetSelectedIndex();
+ }
+
+ template <>
+ void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel)
+ {
+ if(iSel < 0)
+ tCtrl.SelectItem(-1);
+ else
+ tCtrl.SelectItem(iSel);
+ }
+#endif // __ATLCTRLS_H__
+
+ template <class TCtrl>
+ void DDX_Index(UINT nID, INT& nVal, BOOL bSave)
+ {
+ T* pT = static_cast<T*>(this);
+ TCtrl ctrl(pT->GetDlgItem(nID));
+
+ if(bSave)
+ nVal = _getSel(ctrl);
+ else
+ _setSel(ctrl, nVal);
+ }
+
+// Overrideables
+ void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)
+ {
+ // Override to display an error message
+ ::MessageBeep((UINT)-1);
+ T* pT = static_cast<T*>(this);
+ ::SetFocus(pT->GetDlgItem(nCtrlID));
+ }
+
+ void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)
+ {
+ // Override to display an error message
+ ::MessageBeep((UINT)-1);
+ T* pT = static_cast<T*>(this);
+ ::SetFocus(pT->GetDlgItem(nCtrlID));
+ }
+};
+
+}; // namespace WTL
+
+#endif // __ATLDDX_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLDLGS_H__
+#define __ATLDLGS_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atldlgs.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atldlgs.h requires atlwin.h to be included first
+#endif
+
+#include <commdlg.h>
+#include <shlobj.h>
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+ #include <shobjidl.h>
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CFileDialogImpl<T>
+// CFileDialog
+// CFileDialogEx
+// CMultiFileDialogImpl<T>
+// CMultiFileDialog
+// CShellFileDialogImpl<T>
+// CShellFileOpenDialogImpl<T>
+// CShellFileOpenDialog
+// CShellFileSaveDialogImpl<T>
+// CShellFileSaveDialog
+// CFolderDialogImpl<T>
+// CFolderDialog
+// CFontDialogImpl<T>
+// CFontDialog
+// CRichEditFontDialogImpl<T>
+// CRichEditFontDialog
+// CColorDialogImpl<T>
+// CColorDialog
+// CPrintDialogImpl<T>
+// CPrintDialog
+// CPrintDialogExImpl<T>
+// CPrintDialogEx
+// CPageSetupDialogImpl<T>
+// CPageSetupDialog
+// CFindReplaceDialogImpl<T>
+// CFindReplaceDialog
+//
+// CDialogBaseUnits
+// CMemDlgTemplate
+// CIndirectDialogImpl<T, TDlgTemplate, TBase>
+//
+// CPropertySheetWindow
+// CPropertySheetImpl<T, TBase>
+// CPropertySheet
+// CPropertyPageWindow
+// CPropertyPageImpl<T, TBase>
+// CPropertyPage<t_wDlgTemplateID>
+// CAxPropertyPageImpl<T, TBase>
+// CAxPropertyPage<t_wDlgTemplateID>
+//
+// CWizard97SheetWindow
+// CWizard97SheetImpl<T, TBase>
+// CWizard97Sheet
+// CWizard97PageWindow
+// CWizard97PageImpl<T, TBase>
+// CWizard97ExteriorPageImpl<T, TBase>
+// CWizard97InteriorPageImpl<T, TBase>
+//
+// CAeroWizardFrameWindow
+// CAeroWizardFrameImpl<T, TBase>
+// CAeroWizardFrame
+// CAeroWizardPageWindow
+// CAeroWizardPageImpl<T, TBase>
+// CAeroWizardPage<t_wDlgTemplateID>
+// CAeroWizardAxPageImpl<T, TBase>
+// CAeroWizardAxPage<t_wDlgTemplateID>
+//
+// CTaskDialogConfig
+// CTaskDialogImpl<T>
+// CTaskDialog
+//
+// Global functions:
+// AtlTaskDialog()
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CFileDialogImpl - used for File Open or File Save As
+
+// compatibility with the old (vc6.0) headers
+#if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
+ #ifndef CDSIZEOF_STRUCT
+ #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
+ #endif
+ #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
+ #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
+ #ifdef UNICODE
+ #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400W
+ #else
+ #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400A
+ #endif // !UNICODE
+#endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
+
+#if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM)
+ #define CDN_INCLUDEITEM (CDN_FIRST - 0x0007)
+#endif
+
+template <class T>
+class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase
+{
+public:
+#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
+ OPENFILENAMEEX m_ofn;
+#else
+ OPENFILENAME m_ofn;
+#endif
+ BOOL m_bOpenFileDialog; // TRUE for file open, FALSE for file save
+ TCHAR m_szFileTitle[_MAX_FNAME]; // contains file title after return
+ TCHAR m_szFileName[_MAX_PATH]; // contains full path name after return
+
+ CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
+ LPCTSTR lpszDefExt = NULL,
+ LPCTSTR lpszFileName = NULL,
+ DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
+ LPCTSTR lpszFilter = NULL,
+ HWND hWndParent = NULL)
+ {
+ memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
+ m_szFileName[0] = _T('\0');
+ m_szFileTitle[0] = _T('\0');
+
+ m_bOpenFileDialog = bOpenFileDialog;
+
+#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
+ m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME);
+#else
+ m_ofn.lStructSize = sizeof(m_ofn);
+#endif
+
+#if (_WIN32_WINNT >= 0x0500)
+ // adjust struct size if running on older version of Windows
+ if(AtlIsOldWindows())
+ {
+ ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400); // must be
+ m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ }
+#endif // (_WIN32_WINNT >= 0x0500)
+ m_ofn.lpstrFile = m_szFileName;
+ m_ofn.nMaxFile = _MAX_PATH;
+ m_ofn.lpstrDefExt = lpszDefExt;
+ m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
+ m_ofn.nMaxFileTitle = _MAX_FNAME;
+#ifndef _WIN32_WCE
+ m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;
+#else // CE specific
+ m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;
+#endif // !_WIN32_WCE
+ m_ofn.lpstrFilter = lpszFilter;
+ m_ofn.hInstance = ModuleHelper::GetResourceInstance();
+ m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;
+ m_ofn.hwndOwner = hWndParent;
+
+ // setup initial file name
+ if(lpszFileName != NULL)
+ SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);
+ }
+
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);
+ ATLASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook
+
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ if(m_ofn.hwndOwner == NULL) // set only if not specified before
+ m_ofn.hwndOwner = hWndParent;
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);
+
+ BOOL bRet;
+ if(m_bOpenFileDialog)
+#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
+ bRet = ::GetOpenFileNameEx(&m_ofn);
+ else
+ bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn);
+#else
+ bRet = ::GetOpenFileName(&m_ofn);
+ else
+ bRet = ::GetSaveFileName(&m_ofn);
+#endif
+
+ m_hWnd = NULL;
+
+ return bRet ? IDOK : IDCANCEL;
+ }
+
+// Attributes
+ ATL::CWindow GetFileDialogWindow() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ATL::CWindow(GetParent());
+ }
+
+ int GetFilePath(LPTSTR lpstrFilePath, int nLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath);
+ }
+
+ int GetFolderIDList(LPVOID lpBuff, int nLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff);
+ }
+
+ int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath);
+ }
+
+ int GetSpec(LPTSTR lpstrSpec, int nLength) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec);
+ }
+
+ void SetControlText(int nCtrlID, LPCTSTR lpstrText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText);
+ }
+
+ void SetDefExt(LPCTSTR lpstrExt)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt);
+ }
+
+ BOOL GetReadOnlyPref() const // return TRUE if readonly checked
+ {
+ return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE;
+ }
+
+// Operations
+ void HideControl(int nCtrlID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
+
+ GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID);
+ }
+
+// Special override for common dialogs
+ BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0));
+ return TRUE;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CFileDialogImpl)
+ NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK)
+ NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange)
+ NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp)
+ NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone)
+ NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange)
+ NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation)
+ NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange)
+#ifndef _WIN32_WCE
+ NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem)
+#endif // !_WIN32_WCE
+ END_MSG_MAP()
+
+ LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ return !pT->OnFileOK((LPOFNOTIFY)pnmh);
+ }
+
+ LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT->OnFolderChange((LPOFNOTIFY)pnmh);
+ return 0;
+ }
+
+ LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT->OnHelp((LPOFNOTIFY)pnmh);
+ return 0;
+ }
+
+ LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT->OnInitDone((LPOFNOTIFY)pnmh);
+ return 0;
+ }
+
+ LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT->OnSelChange((LPOFNOTIFY)pnmh);
+ return 0;
+ }
+
+ LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ return pT->OnShareViolation((LPOFNOTIFY)pnmh);
+ }
+
+ LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ pT->OnTypeChange((LPOFNOTIFY)pnmh);
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ T* pT = static_cast<T*>(this);
+ return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh);
+ }
+#endif // !_WIN32_WCE
+
+// Overrideables
+ BOOL OnFileOK(LPOFNOTIFY /*lpon*/)
+ {
+ return TRUE;
+ }
+
+ void OnFolderChange(LPOFNOTIFY /*lpon*/)
+ {
+ }
+
+ void OnHelp(LPOFNOTIFY /*lpon*/)
+ {
+ }
+
+ void OnInitDone(LPOFNOTIFY /*lpon*/)
+ {
+ }
+
+ void OnSelChange(LPOFNOTIFY /*lpon*/)
+ {
+ }
+
+ int OnShareViolation(LPOFNOTIFY /*lpon*/)
+ {
+ return 0;
+ }
+
+ void OnTypeChange(LPOFNOTIFY /*lpon*/)
+ {
+ }
+
+#ifndef _WIN32_WCE
+ BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/)
+ {
+ return TRUE; // include item
+ }
+#endif // !_WIN32_WCE
+};
+
+class CFileDialog : public CFileDialogImpl<CFileDialog>
+{
+public:
+ CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
+ LPCTSTR lpszDefExt = NULL,
+ LPCTSTR lpszFileName = NULL,
+ DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
+ LPCTSTR lpszFilter = NULL,
+ HWND hWndParent = NULL)
+ : CFileDialogImpl<CFileDialog>(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
+ { }
+
+ // override base class map and references to handlers
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
+class CFileDialogEx : public CFileDialogImpl<CFileDialogEx>
+{
+public:
+ CFileDialogEx( // Supports only FileOpen
+ LPCTSTR lpszDefExt = NULL,
+ LPCTSTR lpszFileName = NULL,
+ DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
+ OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW,
+ OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO,
+ LPCTSTR lpszFilter = NULL,
+ HWND hWndParent = NULL)
+ : CFileDialogImpl<CFileDialogEx>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
+ {
+ m_ofn.ExFlags = ExFlags;
+ m_ofn.dwSortOrder = dwSortOrder;
+ }
+
+ // override base class map and references to handlers
+ DECLARE_EMPTY_MSG_MAP()
+};
+#endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Multi File Dialog - Multi-select File Open dialog
+
+#ifndef _WIN32_WCE
+
+// The class dynamically resizes the buffer as the file selection changes
+// (as described in Knowledge Base article 131462). It also expands selected
+// shortcut files to take into account the full path of the target file.
+// Note that this doesn't work on Win9x for the old style dialogs, as well as
+// on NT for non-Unicode builds.
+
+#ifndef _WTL_FIXED_OFN_BUFFER_LENGTH
+ #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000
+#endif
+
+template <class T>
+class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T >
+{
+public:
+ mutable LPCTSTR m_pNextFile;
+#ifndef _UNICODE
+ bool m_bIsNT;
+#endif
+
+ CMultiFileDialogImpl(
+ LPCTSTR lpszDefExt = NULL,
+ LPCTSTR lpszFileName = NULL,
+ DWORD dwFlags = OFN_HIDEREADONLY,
+ LPCTSTR lpszFilter = NULL,
+ HWND hWndParent = NULL)
+ : CFileDialogImpl<T>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent),
+ m_pNextFile(NULL)
+ {
+ m_ofn.Flags |= OFN_ALLOWMULTISELECT; // Force multiple selection mode
+
+#ifndef _UNICODE
+ OSVERSIONINFO ovi = { sizeof(ovi) };
+ ::GetVersionEx(&ovi);
+ m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT);
+ if (m_bIsNT)
+ {
+ // On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there
+ // is absolutely nothing we can do except to start off with a large buffer.
+ ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH));
+ }
+#endif
+ }
+
+ ~CMultiFileDialogImpl()
+ {
+ if (m_ofn.lpstrFile != m_szFileName) // Free the buffer if we allocated it
+ delete[] m_ofn.lpstrFile;
+ }
+
+// Operations
+ // Get the directory that the files were chosen from.
+ // The function returns the number of characters copied, not including the terminating zero.
+ // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
+ // If the function fails, the return value is zero.
+ int GetDirectory(LPTSTR pBuffer, int nBufLen) const
+ {
+ if (m_ofn.lpstrFile == NULL)
+ return 0;
+
+ LPCTSTR pStr = m_ofn.lpstrFile;
+ int nLength = lstrlen(pStr);
+ if (pStr[nLength + 1] == 0)
+ {
+ // The OFN buffer contains a single item so extract its path.
+ LPCTSTR pSep = _strrchr(pStr, _T('\\'));
+ if (pSep != NULL)
+ nLength = (int)(DWORD_PTR)(pSep - pStr);
+ }
+
+ int nRet = 0;
+ if (pBuffer == NULL) // If the buffer is NULL, return the required length
+ {
+ nRet = nLength + 1;
+ }
+ else if (nBufLen > nLength)
+ {
+ SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength);
+ nRet = nLength;
+ }
+
+ return nRet;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ bool GetDirectory(_CSTRING_NS::CString& strDir) const
+ {
+ bool bRet = false;
+
+ int nLength = GetDirectory(NULL, 0);
+ if (nLength > 0)
+ {
+ bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0);
+ strDir.ReleaseBuffer(nLength - 1);
+ }
+
+ return bRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ // Get the first filename as a pointer into the buffer.
+ LPCTSTR GetFirstFileName() const
+ {
+ if (m_ofn.lpstrFile == NULL)
+ return NULL;
+
+ m_pNextFile = NULL; // Reset internal buffer pointer
+
+ LPCTSTR pStr = m_ofn.lpstrFile;
+ int nLength = lstrlen(pStr);
+ if (pStr[nLength + 1] != 0)
+ {
+ // Multiple items were selected. The first string is the directory,
+ // so skip forwards to the second string.
+ pStr += nLength + 1;
+
+ // Set up m_pNext so it points to the second item (or null).
+ m_pNextFile = pStr;
+ GetNextFileName();
+ }
+ else
+ {
+ // A single item was selected. Skip forward past the path.
+ LPCTSTR pSep = _strrchr(pStr, _T('\\'));
+ if (pSep != NULL)
+ pStr = pSep + 1;
+ }
+
+ return pStr;
+ }
+
+ // Get the next filename as a pointer into the buffer.
+ LPCTSTR GetNextFileName() const
+ {
+ if (m_pNextFile == NULL)
+ return NULL;
+
+ LPCTSTR pStr = m_pNextFile;
+ // Set "m_pNextFile" to point to the next file name, or null if we
+ // have reached the last file in the list.
+ int nLength = lstrlen(pStr);
+ m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL;
+
+ return pStr;
+ }
+
+ // Get the first filename as a full path.
+ // The function returns the number of characters copied, not including the terminating zero.
+ // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
+ // If the function fails, the return value is zero.
+ int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const
+ {
+ LPCTSTR pStr = GetFirstFileName();
+ int nLengthDir = GetDirectory(NULL, 0);
+ if((pStr == NULL) || (nLengthDir == 0))
+ return 0;
+
+ // Figure out the required length.
+ int nLengthTotal = nLengthDir + lstrlen(pStr);
+
+ int nRet = 0;
+ if(pBuffer == NULL) // If the buffer is NULL, return the required length
+ {
+ nRet = nLengthTotal + 1;
+ }
+ else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
+ {
+ GetDirectory(pBuffer, nBufLen);
+ SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
+ SecureHelper::strcat_x(pBuffer, nBufLen, pStr);
+ nRet = nLengthTotal;
+ }
+
+ return nRet;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ bool GetFirstPathName(_CSTRING_NS::CString& strPath) const
+ {
+ bool bRet = false;
+
+ int nLength = GetFirstPathName(NULL, 0);
+ if (nLength > 0)
+ {
+ bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0);
+ strPath.ReleaseBuffer(nLength - 1);
+ }
+
+ return bRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ // Get the next filename as a full path.
+ // The function returns the number of characters copied, not including the terminating zero.
+ // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
+ // If the function fails, the return value is zero.
+ // The internal position marker is moved forward only if the function succeeds and the buffer was large enough.
+ int GetNextPathName(LPTSTR pBuffer, int nBufLen) const
+ {
+ if (m_pNextFile == NULL)
+ return 0;
+
+ int nRet = 0;
+ LPCTSTR pStr = m_pNextFile;
+ // Does the filename contain a backslash?
+ if (_strrchr(pStr, _T('\\')) != NULL)
+ {
+ // Yes, so we'll assume it's a full path.
+ int nLength = lstrlen(pStr);
+
+ if (pBuffer == NULL) // If the buffer is NULL, return the required length
+ {
+ nRet = nLength + 1;
+ }
+ else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename
+ {
+ SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName());
+ nRet = nBufLen;
+ }
+ }
+ else
+ {
+ // The filename is relative, so construct the full path.
+ int nLengthDir = GetDirectory(NULL, 0);
+ if (nLengthDir > 0)
+ {
+ // Calculate the required space.
+ int nLengthTotal = nLengthDir + lstrlen(pStr);
+
+ if(pBuffer == NULL) // If the buffer is NULL, return the required length
+ {
+ nRet = nLengthTotal + 1;
+ }
+ else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
+ {
+ GetDirectory(pBuffer, nBufLen);
+ SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
+ SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName());
+ nRet = nLengthTotal;
+ }
+ }
+ }
+
+ return nRet;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ bool GetNextPathName(_CSTRING_NS::CString& strPath) const
+ {
+ bool bRet = false;
+
+ int nLength = GetNextPathName(NULL, 0);
+ if (nLength > 0)
+ {
+ bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0);
+ strPath.ReleaseBuffer(nLength - 1);
+ }
+
+ return bRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+// Implementation
+ bool ResizeFilenameBuffer(DWORD dwLength)
+ {
+ if (dwLength > m_ofn.nMaxFile)
+ {
+ // Free the old buffer.
+ if (m_ofn.lpstrFile != m_szFileName)
+ {
+ delete[] m_ofn.lpstrFile;
+ m_ofn.lpstrFile = NULL;
+ m_ofn.nMaxFile = 0;
+ }
+
+ // Allocate the new buffer.
+ LPTSTR lpstrBuff = NULL;
+ ATLTRY(lpstrBuff = new TCHAR[dwLength]);
+ if (lpstrBuff != NULL)
+ {
+ m_ofn.lpstrFile = lpstrBuff;
+ m_ofn.lpstrFile[0] = 0;
+ m_ofn.nMaxFile = dwLength;
+ }
+ }
+
+ return (m_ofn.lpstrFile != NULL);
+ }
+
+ void OnSelChange(LPOFNOTIFY /*lpon*/)
+ {
+#ifndef _UNICODE
+ // There is no point resizing the buffer in ANSI builds running on NT.
+ if (m_bIsNT)
+ return;
+#endif
+
+ // Get the buffer length required to hold the spec.
+ int nLength = GetSpec(NULL, 0);
+ if (nLength <= 1)
+ return; // no files are selected, presumably
+
+ // Add room for the directory, and an extra terminating zero.
+ nLength += GetFolderPath(NULL, 0) + 1;
+
+ if (!ResizeFilenameBuffer(nLength))
+ {
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ // If we are not following links then our work is done.
+ if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0)
+ return;
+
+ // Get the file spec, which is the text in the edit control.
+ if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0)
+ return;
+
+ // Get the ID-list of the current folder.
+ int nBytes = GetFolderIDList(NULL, 0);
+ CTempBuffer<ITEMIDLIST> idlist;
+ idlist.AllocateBytes(nBytes);
+ if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0))
+ return;
+
+ // First bind to the desktop folder, then to the current folder.
+ ATL::CComPtr<IShellFolder> pDesktop, pFolder;
+ if (FAILED(::SHGetDesktopFolder(&pDesktop)))
+ return;
+ if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder)))
+ return;
+
+ // Work through the file spec, looking for quoted filenames. If we find a shortcut file, then
+ // we need to add enough extra buffer space to hold its target path.
+ DWORD nExtraChars = 0;
+ bool bInsideQuotes = false;
+ LPCTSTR pAnchor = m_ofn.lpstrFile;
+ LPCTSTR pChar = m_ofn.lpstrFile;
+ for ( ; *pChar; ++pChar)
+ {
+ // Look for quotation marks.
+ if (*pChar == _T('\"'))
+ {
+ // We are either entering or leaving a passage of quoted text.
+ bInsideQuotes = !bInsideQuotes;
+
+ // Is it an opening or closing quote?
+ if (bInsideQuotes)
+ {
+ // We found an opening quote, so set "pAnchor" to the following character.
+ pAnchor = pChar + 1;
+ }
+ else // closing quote
+ {
+ // Each quoted entity should be shorter than MAX_PATH.
+ if (pChar - pAnchor >= MAX_PATH)
+ return;
+
+ // Get the ID-list and attributes of the file.
+ USES_CONVERSION;
+ int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor);
+ TCHAR szFileName[MAX_PATH];
+ SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength);
+ LPITEMIDLIST pidl = NULL;
+ DWORD dwAttrib = SFGAO_LINK;
+ if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib)))
+ {
+ // Is it a shortcut file?
+ if (dwAttrib & SFGAO_LINK)
+ {
+ // Bind to its IShellLink interface.
+ ATL::CComPtr<IShellLink> pLink;
+ if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink)))
+ {
+ // Get the shortcut's target path.
+ TCHAR szPath[MAX_PATH];
+ if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0)))
+ {
+ // If the target path is longer than the shortcut name, then add on the number
+ // of extra characters that are required.
+ int nNewLength = lstrlen(szPath);
+ if (nNewLength > nFileNameLength)
+ nExtraChars += nNewLength - nFileNameLength;
+ }
+ }
+ }
+
+ // Free the ID-list returned by ParseDisplayName.
+ ::CoTaskMemFree(pidl);
+ }
+ }
+ }
+ }
+
+ // If we need more space for shortcut targets, then reallocate.
+ if (nExtraChars > 0)
+ ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars));
+ }
+
+ // Helper for _ATL_MIN_CRT
+ static const TCHAR* _strrchr(const TCHAR* p, TCHAR ch)
+ {
+#ifndef _ATL_MIN_CRT
+ return _tcsrchr(p, ch);
+#else // _ATL_MIN_CRT
+ const TCHAR* lpsz = NULL;
+ while (*p != 0)
+ {
+ if (*p == ch)
+ lpsz = p;
+ p = ::CharNext(p);
+ }
+ return lpsz;
+#endif // _ATL_MIN_CRT
+ }
+};
+
+class CMultiFileDialog : public CMultiFileDialogImpl<CMultiFileDialog>
+{
+public:
+ CMultiFileDialog(
+ LPCTSTR lpszDefExt = NULL,
+ LPCTSTR lpszFileName = NULL,
+ DWORD dwFlags = OFN_HIDEREADONLY,
+ LPCTSTR lpszFilter = NULL,
+ HWND hWndParent = NULL)
+ : CMultiFileDialogImpl<CMultiFileDialog>(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
+ { }
+
+ BEGIN_MSG_MAP(CMultiFileDialog)
+ CHAIN_MSG_MAP(CMultiFileDialogImpl<CMultiFileDialog>)
+ END_MSG_MAP()
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Shell File Dialog - new Shell File Open and Save dialogs in Vista
+
+// Note: Use GetPtr() to access dialog interface methods.
+// Example:
+// CShellFileOpenDialog dlg;
+// dlg.GetPtr()->SetTitle(L"MyFileOpenDialog");
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+
+///////////////////////////////////////////////////////////////////////////////
+// CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl
+
+template <class T>
+class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents
+{
+public:
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ INT_PTR nRet = -1;
+
+ T* pT = static_cast<T*>(this);
+ if(pT->m_spFileDlg == NULL)
+ {
+ ATLASSERT(FALSE);
+ return nRet;
+ }
+
+ DWORD dwCookie = 0;
+ pT->_Advise(dwCookie);
+
+ HRESULT hRet = pT->m_spFileDlg->Show(hWndParent);
+ if(SUCCEEDED(hRet))
+ nRet = IDOK;
+ else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED))
+ nRet = IDCANCEL;
+ else
+ ATLASSERT(FALSE); // error
+
+ pT->_Unadvise(dwCookie);
+
+ return nRet;
+ }
+
+ bool IsNull() const
+ {
+ const T* pT = static_cast<const T*>(this);
+ return (pT->m_spFileDlg == NULL);
+ }
+
+// Operations - get file path after dialog returns
+ HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+
+ ATL::CComPtr<IShellItem> spItem;
+ HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
+
+ if(SUCCEEDED(hRet))
+ hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength);
+
+ return hRet;
+ }
+
+ HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+
+ ATL::CComPtr<IShellItem> spItem;
+ HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
+
+ if(SUCCEEDED(hRet))
+ hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength);
+
+ return hRet;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+
+ ATL::CComPtr<IShellItem> spItem;
+ HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
+
+ if(SUCCEEDED(hRet))
+ hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath);
+
+ return hRet;
+ }
+
+ HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+
+ ATL::CComPtr<IShellItem> spItem;
+ HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
+
+ if(SUCCEEDED(hRet))
+ hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle);
+
+ return hRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+// Helpers for IShellItem
+ static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength)
+ {
+ ATLASSERT(pShellItem != NULL);
+
+ LPWSTR lpstrName = NULL;
+ HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
+
+ if(SUCCEEDED(hRet))
+ {
+ if(lstrlenW(lpstrName) < cchLength)
+ {
+ SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName);
+ }
+ else
+ {
+ ATLASSERT(FALSE);
+ hRet = DISP_E_BUFFERTOOSMALL;
+ }
+
+ ::CoTaskMemFree(lpstrName);
+ }
+
+ return hRet;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str)
+ {
+ ATLASSERT(pShellItem != NULL);
+
+ LPWSTR lpstrName = NULL;
+ HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
+
+ if(SUCCEEDED(hRet))
+ {
+ str = lpstrName;
+ ::CoTaskMemFree(lpstrName);
+ }
+
+ return hRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+// Implementation
+ void _Advise(DWORD& dwCookie)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+ HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie);
+ ATLVERIFY(SUCCEEDED(hRet));
+ }
+
+ void _Unadvise(DWORD dwCookie)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+ HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie);
+ ATLVERIFY(SUCCEEDED(hRet));
+ }
+
+ void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg != NULL);
+
+ HRESULT hRet = E_FAIL;
+
+ if(lpszFileName != NULL)
+ {
+ hRet = pT->m_spFileDlg->SetFileName(lpszFileName);
+ ATLASSERT(SUCCEEDED(hRet));
+ }
+
+ hRet = pT->m_spFileDlg->SetOptions(dwOptions);
+ ATLASSERT(SUCCEEDED(hRet));
+
+ if(lpszDefExt != NULL)
+ {
+ hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt);
+ ATLASSERT(SUCCEEDED(hRet));
+ }
+
+ if(arrFilterSpec != NULL && uFilterSpecCount != 0U)
+ {
+ hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec);
+ ATLASSERT(SUCCEEDED(hRet));
+ }
+ }
+
+// Implementation - IUnknown interface
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
+ {
+ if(ppvObject == NULL)
+ return E_POINTER;
+
+ T* pT = static_cast<T*>(this);
+ if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents))
+ {
+ *ppvObject = (IFileDialogEvents*)pT;
+ // AddRef() not needed
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return 1;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ return 1;
+ }
+
+// Implementation - IFileDialogEvents interface
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnFileOk();
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnFolderChanging(psiFolder);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnFolderChange();
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnSelectionChange();
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnShareViolation(psi, pResponse);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnTypeChange();
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
+ pfd; // avoid level 4 warning
+ return pT->OnOverwrite(psi, pResponse);
+ }
+
+// Overrideables - Event handlers
+ HRESULT OnFileOk()
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnFolderChanging(IShellItem* /*psiFolder*/)
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnFolderChange()
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnSelectionChange()
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/)
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnTypeChange()
+ {
+ return E_NOTIMPL;
+ }
+
+ HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/)
+ {
+ return E_NOTIMPL;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CShellFileOpenDialogImpl - implements new Shell File Open dialog
+
+template <class T>
+class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T >
+{
+public:
+ ATL::CComPtr<IFileOpenDialog> m_spFileDlg;
+
+ CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL,
+ DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST,
+ LPCWSTR lpszDefExt = NULL,
+ const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
+ UINT uFilterSpecCount = 0U)
+ {
+ HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog);
+
+ if(SUCCEEDED(hRet))
+ _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
+ }
+
+ IFileOpenDialog* GetPtr()
+ {
+ return m_spFileDlg;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CShellFileOpenDialog - new Shell File Open dialog without events
+
+class CShellFileOpenDialog : public CShellFileOpenDialogImpl<CShellFileOpenDialog>
+{
+public:
+ CShellFileOpenDialog(LPCWSTR lpszFileName = NULL,
+ DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST,
+ LPCWSTR lpszDefExt = NULL,
+ const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
+ UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl<CShellFileOpenDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
+ { }
+
+// Implementation (remove _Advise/_Unadvise code using template magic)
+ void _Advise(DWORD& /*dwCookie*/)
+ { }
+
+ void _Unadvise(DWORD /*dwCookie*/)
+ { }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CShellFileSaveDialogImpl - implements new Shell File Save dialog
+
+template <class T>
+class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T >
+{
+public:
+ ATL::CComPtr<IFileSaveDialog> m_spFileDlg;
+
+ CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL,
+ DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
+ LPCWSTR lpszDefExt = NULL,
+ const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
+ UINT uFilterSpecCount = 0U)
+ {
+ HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog);
+
+ if(SUCCEEDED(hRet))
+ _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
+ }
+
+ IFileSaveDialog* GetPtr()
+ {
+ return m_spFileDlg;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CShellFileSaveDialog - new Shell File Save dialog without events
+
+class CShellFileSaveDialog : public CShellFileSaveDialogImpl<CShellFileSaveDialog>
+{
+public:
+ CShellFileSaveDialog(LPCWSTR lpszFileName = NULL,
+ DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
+ LPCWSTR lpszDefExt = NULL,
+ const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
+ UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl<CShellFileSaveDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
+ { }
+
+// Implementation (remove _Advise/_Unadvise code using template magic)
+ void _Advise(DWORD& /*dwCookie*/)
+ { }
+
+ void _Unadvise(DWORD /*dwCookie*/)
+ { }
+};
+
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFolderDialogImpl - used for browsing for a folder
+
+#ifndef _WIN32_WCE
+
+template <class T>
+class ATL_NO_VTABLE CFolderDialogImpl
+{
+public:
+ BROWSEINFO m_bi;
+ LPCTSTR m_lpstrInitialFolder;
+ LPCITEMIDLIST m_pidlInitialSelection;
+ bool m_bExpandInitialSelection;
+ TCHAR m_szFolderDisplayName[MAX_PATH];
+ TCHAR m_szFolderPath[MAX_PATH];
+ LPITEMIDLIST m_pidlSelected;
+ HWND m_hWnd; // used only in the callback function
+
+// Constructor
+ CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) :
+ m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL)
+ {
+ memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL
+
+ m_bi.hwndOwner = hWndParent;
+ m_bi.pidlRoot = NULL;
+ m_bi.pszDisplayName = m_szFolderDisplayName;
+ m_bi.lpszTitle = lpstrTitle;
+ m_bi.ulFlags = uFlags;
+ m_bi.lpfn = BrowseCallbackProc;
+ m_bi.lParam = (LPARAM)static_cast<T*>(this);
+
+ m_szFolderPath[0] = 0;
+ m_szFolderDisplayName[0] = 0;
+ }
+
+ ~CFolderDialogImpl()
+ {
+ ::CoTaskMemFree(m_pidlSelected);
+ }
+
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ if(m_bi.hwndOwner == NULL) // set only if not specified before
+ m_bi.hwndOwner = hWndParent;
+
+ // Clear out any previous results
+ m_szFolderPath[0] = 0;
+ m_szFolderDisplayName[0] = 0;
+ ::CoTaskMemFree(m_pidlSelected);
+
+ INT_PTR nRet = IDCANCEL;
+ m_pidlSelected = ::SHBrowseForFolder(&m_bi);
+
+ if(m_pidlSelected != NULL)
+ {
+ nRet = IDOK;
+
+ // If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path.
+ // Otherwise, the caller must handle the ID-list directly.
+ if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0)
+ {
+ if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE)
+ nRet = IDCANCEL;
+ }
+ }
+
+ return nRet;
+ }
+
+ // Methods to call before DoModal
+ void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true)
+ {
+ // lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified
+ m_lpstrInitialFolder = lpstrInitialFolder;
+ m_bExpandInitialSelection = bExpand;
+ }
+
+ void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true)
+ {
+ m_pidlInitialSelection = pidl;
+ m_bExpandInitialSelection = bExpand;
+ }
+
+ // Methods to call after DoModal
+ LPITEMIDLIST GetSelectedItem(bool bDetach = false)
+ {
+ LPITEMIDLIST pidl = m_pidlSelected;
+ if(bDetach)
+ m_pidlSelected = NULL;
+
+ return pidl;
+ }
+
+ LPCTSTR GetFolderPath() const
+ {
+ return m_szFolderPath;
+ }
+
+ LPCTSTR GetFolderDisplayName() const
+ {
+ return m_szFolderDisplayName;
+ }
+
+ int GetFolderImageIndex() const
+ {
+ return m_bi.iImage;
+ }
+
+// Callback function and overrideables
+ static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+ {
+#ifndef BFFM_VALIDATEFAILED
+ #ifdef UNICODE
+ const int BFFM_VALIDATEFAILED = 4;
+ #else
+ const int BFFM_VALIDATEFAILED = 3;
+ #endif
+#endif // !BFFM_VALIDATEFAILED
+#ifndef BFFM_IUNKNOWN
+ const int BFFM_IUNKNOWN = 5;
+#endif // !BFFM_IUNKNOWN
+#ifndef BIF_NEWDIALOGSTYLE
+ const UINT BIF_NEWDIALOGSTYLE = 0x0040;
+#endif // !BIF_NEWDIALOGSTYLE
+
+ int nRet = 0;
+ T* pT = (T*)lpData;
+ bool bClear = false;
+ if(pT->m_hWnd == NULL)
+ {
+ pT->m_hWnd = hWnd;
+ bClear = true;
+ }
+ else
+ {
+ ATLASSERT(pT->m_hWnd == hWnd);
+ }
+
+ switch(uMsg)
+ {
+ case BFFM_INITIALIZED:
+ // Set initial selection
+ // Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder
+ if(pT->m_pidlInitialSelection != NULL)
+ pT->SetSelection(pT->m_pidlInitialSelection);
+ else if(pT->m_lpstrInitialFolder != NULL)
+ pT->SetSelection(pT->m_lpstrInitialFolder);
+
+ // Expand initial selection if appropriate
+ if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0))
+ {
+ if(pT->m_pidlInitialSelection != NULL)
+ pT->SetExpanded(pT->m_pidlInitialSelection);
+ else if(pT->m_lpstrInitialFolder != NULL)
+ pT->SetExpanded(pT->m_lpstrInitialFolder);
+ }
+ pT->OnInitialized();
+ break;
+ case BFFM_SELCHANGED:
+ pT->OnSelChanged((LPITEMIDLIST)lParam);
+ break;
+ case BFFM_VALIDATEFAILED:
+ nRet = pT->OnValidateFailed((LPCTSTR)lParam);
+ break;
+ case BFFM_IUNKNOWN:
+ pT->OnIUnknown((IUnknown*)lParam);
+ break;
+ default:
+ ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n"));
+ break;
+ }
+
+ if(bClear)
+ pT->m_hWnd = NULL;
+ return nRet;
+ }
+
+ void OnInitialized()
+ {
+ }
+
+ void OnSelChanged(LPITEMIDLIST /*pItemIDList*/)
+ {
+ }
+
+ int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/)
+ {
+ return 1; // 1=continue, 0=EndDialog
+ }
+
+ void OnIUnknown(IUnknown* /*pUnknown*/)
+ {
+ }
+
+ // Commands - valid to call only from handlers
+ void EnableOK(BOOL bEnable)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable);
+ }
+
+ void SetSelection(LPCITEMIDLIST pItemIDList)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList);
+ }
+
+ void SetSelection(LPCTSTR lpstrFolderPath)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath);
+ }
+
+ void SetStatusText(LPCTSTR lpstrText)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText);
+ }
+
+ void SetOKText(LPCTSTR lpstrOKText)
+ {
+#ifndef BFFM_SETOKTEXT
+ const UINT BFFM_SETOKTEXT = WM_USER + 105;
+#endif
+ ATLASSERT(m_hWnd != NULL);
+ USES_CONVERSION;
+ LPCWSTR lpstr = T2CW(lpstrOKText);
+ ::SendMessage(m_hWnd, BFFM_SETOKTEXT, 0, (LPARAM)lpstr);
+ }
+
+ void SetExpanded(LPCITEMIDLIST pItemIDList)
+ {
+#ifndef BFFM_SETEXPANDED
+ const UINT BFFM_SETEXPANDED = WM_USER + 106;
+#endif
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList);
+ }
+
+ void SetExpanded(LPCTSTR lpstrFolderPath)
+ {
+#ifndef BFFM_SETEXPANDED
+ const UINT BFFM_SETEXPANDED = WM_USER + 106;
+#endif
+ ATLASSERT(m_hWnd != NULL);
+ USES_CONVERSION;
+ LPCWSTR lpstr = T2CW(lpstrFolderPath);
+ ::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr);
+ }
+};
+
+class CFolderDialog : public CFolderDialogImpl<CFolderDialog>
+{
+public:
+ CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS)
+ : CFolderDialogImpl<CFolderDialog>(hWndParent, lpstrTitle, uFlags)
+ { }
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCommonDialogImplBase - base class for common dialog classes
+
+class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase
+{
+public:
+ static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ if(uMsg != WM_INITDIALOG)
+ return 0;
+ CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
+ ATLASSERT(pT != NULL);
+ ATLASSERT(pT->m_hWnd == NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ // subclass dialog's window
+ if(!pT->SubclassWindow(hWnd))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n"));
+ return 0;
+ }
+ // check message map for WM_INITDIALOG handler
+ LRESULT lRes = 0;
+ if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
+ return 0;
+ return lRes;
+ }
+
+// Special override for common dialogs
+ BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
+ return TRUE;
+ }
+
+// Implementation - try to override these, to prevent errors
+ HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID)
+ {
+ ATLASSERT(FALSE); // should not be called
+ return NULL;
+ }
+
+ static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
+ {
+ ATLASSERT(FALSE); // should not be called
+ return 0;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFontDialogImpl - font selection dialog
+
+#ifndef _WIN32_WCE
+
+template <class T>
+class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase
+{
+public:
+ enum { _cchStyleName = 64 };
+
+ CHOOSEFONT m_cf;
+ TCHAR m_szStyleName[_cchStyleName]; // contains style name after return
+ LOGFONT m_lf; // default LOGFONT to store the info
+
+// Constructors
+ CFontDialogImpl(LPLOGFONT lplfInitial = NULL,
+ DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
+ HDC hDCPrinter = NULL,
+ HWND hWndParent = NULL)
+ {
+ memset(&m_cf, 0, sizeof(m_cf));
+ memset(&m_lf, 0, sizeof(m_lf));
+ memset(&m_szStyleName, 0, sizeof(m_szStyleName));
+
+ m_cf.lStructSize = sizeof(m_cf);
+ m_cf.hwndOwner = hWndParent;
+ m_cf.rgbColors = RGB(0, 0, 0);
+ m_cf.lpszStyle = (LPTSTR)&m_szStyleName;
+ m_cf.Flags = dwFlags | CF_ENABLEHOOK;
+ m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc;
+
+ if(lplfInitial != NULL)
+ {
+ m_cf.lpLogFont = lplfInitial;
+ m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
+ m_lf = *lplfInitial;
+ }
+ else
+ {
+ m_cf.lpLogFont = &m_lf;
+ }
+
+ if(hDCPrinter != NULL)
+ {
+ m_cf.hDC = hDCPrinter;
+ m_cf.Flags |= CF_PRINTERFONTS;
+ }
+ }
+
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0);
+ ATLASSERT(m_cf.lpfnHook != NULL); // can still be a user hook
+
+ if(m_cf.hwndOwner == NULL) // set only if not specified before
+ m_cf.hwndOwner = hWndParent;
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
+
+ BOOL bRet = ::ChooseFont(&m_cf);
+
+ m_hWnd = NULL;
+
+ if(bRet) // copy logical font from user's initialization buffer (if needed)
+ SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf));
+
+ return bRet ? IDOK : IDCANCEL;
+ }
+
+ // works only when the dialog is dislayed or after
+ void GetCurrentFont(LPLOGFONT lplf) const
+ {
+ ATLASSERT(lplf != NULL);
+
+ if(m_hWnd != NULL)
+ ::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf);
+ else
+ *lplf = m_lf;
+ }
+
+ // works only when the dialog is dislayed or before
+#ifndef _WIN32_WCE
+ void SetLogFont(LPLOGFONT lplf)
+ {
+ ATLASSERT(lplf != NULL);
+#ifndef WM_CHOOSEFONT_SETLOGFONT
+ const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101);
+#endif
+ if(m_hWnd != NULL)
+ {
+ ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf);
+ }
+ else
+ {
+ m_lf = *lplf;
+ m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
+ }
+ }
+
+ void SetFlags(DWORD dwFlags)
+ {
+#ifndef WM_CHOOSEFONT_SETFLAGS
+ const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102);
+#endif
+ if(m_hWnd != NULL)
+ {
+ CHOOSEFONT cf = { sizeof(CHOOSEFONT) };
+ cf.Flags = dwFlags;
+ ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf);
+ }
+ else
+ {
+ m_cf.Flags = dwFlags;
+ }
+ }
+#endif // !_WIN32_WCE
+
+ // Helpers for parsing information after successful return
+ LPCTSTR GetFaceName() const // return the face name of the font
+ {
+ return (LPCTSTR)m_cf.lpLogFont->lfFaceName;
+ }
+
+ LPCTSTR GetStyleName() const // return the style name of the font
+ {
+ return m_cf.lpszStyle;
+ }
+
+ int GetSize() const // return the pt size of the font
+ {
+ return m_cf.iPointSize;
+ }
+
+ COLORREF GetColor() const // return the color of the font
+ {
+ return m_cf.rgbColors;
+ }
+
+ int GetWeight() const // return the chosen font weight
+ {
+ return (int)m_cf.lpLogFont->lfWeight;
+ }
+
+ BOOL IsStrikeOut() const // return TRUE if strikeout
+ {
+ return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE;
+ }
+
+ BOOL IsUnderline() const // return TRUE if underline
+ {
+ return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE;
+ }
+
+ BOOL IsBold() const // return TRUE if bold font
+ {
+ return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE;
+ }
+
+ BOOL IsItalic() const // return TRUE if italic font
+ {
+ return m_cf.lpLogFont->lfItalic ? TRUE : FALSE;
+ }
+};
+
+class CFontDialog : public CFontDialogImpl<CFontDialog>
+{
+public:
+ CFontDialog(LPLOGFONT lplfInitial = NULL,
+ DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
+ HDC hDCPrinter = NULL,
+ HWND hWndParent = NULL)
+ : CFontDialogImpl<CFontDialog>(lplfInitial, dwFlags, hDCPrinter, hWndParent)
+ { }
+
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRichEditFontDialogImpl - font selection for the Rich Edit ctrl
+
+#if defined(_RICHEDIT_) && !defined(_WIN32_WCE)
+
+template <class T>
+class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T >
+{
+public:
+ CRichEditFontDialogImpl(const CHARFORMAT& charformat,
+ DWORD dwFlags = CF_SCREENFONTS,
+ HDC hDCPrinter = NULL,
+ HWND hWndParent = NULL)
+ : CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent)
+ {
+ m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
+ m_cf.Flags |= FillInLogFont(charformat);
+ m_cf.lpLogFont = &m_lf;
+
+ if((charformat.dwMask & CFM_COLOR) != 0)
+ m_cf.rgbColors = charformat.crTextColor;
+ }
+
+ void GetCharFormat(CHARFORMAT& cf) const
+ {
+ USES_CONVERSION;
+ cf.dwEffects = 0;
+ cf.dwMask = 0;
+ if((m_cf.Flags & CF_NOSTYLESEL) == 0)
+ {
+ cf.dwMask |= CFM_BOLD | CFM_ITALIC;
+ cf.dwEffects |= IsBold() ? CFE_BOLD : 0;
+ cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0;
+ }
+ if((m_cf.Flags & CF_NOSIZESEL) == 0)
+ {
+ cf.dwMask |= CFM_SIZE;
+ // GetSize() returns in tenths of points so mulitply by 2 to get twips
+ cf.yHeight = GetSize() * 2;
+ }
+
+ if((m_cf.Flags & CF_NOFACESEL) == 0)
+ {
+ cf.dwMask |= CFM_FACE;
+ cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily;
+#if (_RICHEDIT_VER >= 0x0200)
+ SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName());
+#else // !(_RICHEDIT_VER >= 0x0200)
+ SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName()));
+#endif // !(_RICHEDIT_VER >= 0x0200)
+ }
+
+ if((m_cf.Flags & CF_EFFECTS) != 0)
+ {
+ cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
+ cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0;
+ cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0;
+ cf.crTextColor = GetColor();
+ }
+ if((m_cf.Flags & CF_NOSCRIPTSEL) == 0)
+ {
+ cf.bCharSet = m_cf.lpLogFont->lfCharSet;
+ cf.dwMask |= CFM_CHARSET;
+ }
+ cf.yOffset = 0;
+ }
+
+ DWORD FillInLogFont(const CHARFORMAT& cf)
+ {
+ USES_CONVERSION;
+ DWORD dwFlags = 0;
+ if((cf.dwMask & CFM_SIZE) != 0)
+ {
+ HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
+ LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY);
+ m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440);
+ }
+ else
+ m_lf.lfHeight = 0;
+
+ m_lf.lfWidth = 0;
+ m_lf.lfEscapement = 0;
+ m_lf.lfOrientation = 0;
+
+ if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD))
+ {
+ m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL;
+ m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE);
+ }
+ else
+ {
+ dwFlags |= CF_NOSTYLESEL;
+ m_lf.lfWeight = FW_DONTCARE;
+ m_lf.lfItalic = FALSE;
+ }
+
+ if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR))
+ {
+ dwFlags |= CF_EFFECTS;
+ m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE);
+ m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE);
+ }
+ else
+ {
+ m_lf.lfUnderline = (BYTE)FALSE;
+ m_lf.lfStrikeOut = (BYTE)FALSE;
+ }
+
+ if((cf.dwMask & CFM_CHARSET) != 0)
+ m_lf.lfCharSet = cf.bCharSet;
+ else
+ dwFlags |= CF_NOSCRIPTSEL;
+ m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ m_lf.lfQuality = DEFAULT_QUALITY;
+ if((cf.dwMask & CFM_FACE) != 0)
+ {
+ m_lf.lfPitchAndFamily = cf.bPitchAndFamily;
+#if (_RICHEDIT_VER >= 0x0200)
+ SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName);
+#else // !(_RICHEDIT_VER >= 0x0200)
+ SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName));
+#endif // !(_RICHEDIT_VER >= 0x0200)
+ }
+ else
+ {
+ m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
+ m_lf.lfFaceName[0] = (TCHAR)0;
+ }
+ return dwFlags;
+ }
+};
+
+class CRichEditFontDialog : public CRichEditFontDialogImpl<CRichEditFontDialog>
+{
+public:
+ CRichEditFontDialog(const CHARFORMAT& charformat,
+ DWORD dwFlags = CF_SCREENFONTS,
+ HDC hDCPrinter = NULL,
+ HWND hWndParent = NULL)
+ : CRichEditFontDialogImpl<CRichEditFontDialog>(charformat, dwFlags, hDCPrinter, hWndParent)
+ { }
+
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CColorDialogImpl - color selection
+
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
+
+#ifdef _WIN32_WCE
+ #pragma comment(lib, "commdlg.lib")
+
+ #ifndef SETRGBSTRING
+ #define SETRGBSTRING _T("commdlg_SetRGBColor")
+ #endif
+
+ #ifndef COLOROKSTRING
+ #define COLOROKSTRING _T("commdlg_ColorOK")
+ #endif
+#endif
+
+template <class T>
+class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase
+{
+public:
+ CHOOSECOLOR m_cc;
+
+// Constructor
+ CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
+ {
+ memset(&m_cc, 0, sizeof(m_cc));
+
+ m_cc.lStructSize = sizeof(m_cc);
+ m_cc.lpCustColors = GetCustomColors();
+ m_cc.hwndOwner = hWndParent;
+ m_cc.Flags = dwFlags | CC_ENABLEHOOK;
+ m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc;
+
+ if(clrInit != 0)
+ {
+ m_cc.rgbResult = clrInit;
+ m_cc.Flags |= CC_RGBINIT;
+ }
+ }
+
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0);
+ ATLASSERT(m_cc.lpfnHook != NULL); // can still be a user hook
+
+ if(m_cc.hwndOwner == NULL) // set only if not specified before
+ m_cc.hwndOwner = hWndParent;
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
+
+ BOOL bRet = ::ChooseColor(&m_cc);
+
+ m_hWnd = NULL;
+
+ return bRet ? IDOK : IDCANCEL;
+ }
+
+ // Set the current color while dialog is displayed
+ void SetCurrentColor(COLORREF clr)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr);
+ }
+
+ // Get the selected color after DoModal returns, or in OnColorOK
+ COLORREF GetColor() const
+ {
+ return m_cc.rgbResult;
+ }
+
+// Special override for the color dialog
+ static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage())
+ return 0;
+
+ LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam;
+ CCommonDialogImplBase* pT = NULL;
+
+ if(uMsg == WM_INITDIALOG)
+ {
+ pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
+ lpCC->lCustData = (LPARAM)pT;
+ ATLASSERT(pT != NULL);
+ ATLASSERT(pT->m_hWnd == NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ // subclass dialog's window
+ if(!pT->SubclassWindow(hWnd))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n"));
+ return 0;
+ }
+ }
+ else if(uMsg == _GetColorOKMessage())
+ {
+ pT = (CCommonDialogImplBase*)lpCC->lCustData;
+ ATLASSERT(pT != NULL);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ }
+
+ // pass to the message map
+ LRESULT lRes;
+ if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
+ return 0;
+ return lRes;
+ }
+
+// Helpers
+ static COLORREF* GetCustomColors()
+ {
+ static COLORREF rgbCustomColors[16] =
+ {
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ RGB(255, 255, 255), RGB(255, 255, 255),
+ };
+
+ return rgbCustomColors;
+ }
+
+ static UINT _GetSetRGBMessage()
+ {
+ static UINT uSetRGBMessage = 0;
+ if(uSetRGBMessage == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uSetRGBMessage == 0)
+ uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING);
+
+ lock.Unlock();
+ }
+ ATLASSERT(uSetRGBMessage != 0);
+ return uSetRGBMessage;
+ }
+
+ static UINT _GetColorOKMessage()
+ {
+ static UINT uColorOKMessage = 0;
+ if(uColorOKMessage == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uColorOKMessage == 0)
+ uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING);
+
+ lock.Unlock();
+ }
+ ATLASSERT(uColorOKMessage != 0);
+ return uColorOKMessage;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CColorDialogImpl)
+ MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK)
+ END_MSG_MAP()
+
+ LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&)
+ {
+ T* pT = static_cast<T*>(this);
+ return pT->OnColorOK();
+ }
+
+// Overrideable
+ BOOL OnColorOK() // validate color
+ {
+ return FALSE;
+ }
+};
+
+class CColorDialog : public CColorDialogImpl<CColorDialog>
+{
+public:
+ CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
+ : CColorDialogImpl<CColorDialog>(clrInit, dwFlags, hWndParent)
+ { }
+
+ // override base class map and references to handlers
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrintDialogImpl - used for Print... and PrintSetup...
+
+#ifndef _WIN32_WCE
+
+// global helper
+static HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode)
+{
+ if(hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames);
+ LPDEVMODE lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL;
+
+ if(lpDevNames == NULL)
+ return NULL;
+
+ HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset,
+ (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset,
+ (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset,
+ lpDevMode);
+
+ ::GlobalUnlock(hDevNames);
+ if(hDevMode != NULL)
+ ::GlobalUnlock(hDevMode);
+ return hDC;
+}
+
+template <class T>
+class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase
+{
+public:
+ // print dialog parameter block (note this is a reference)
+ PRINTDLG& m_pd;
+
+// Constructors
+ CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE, // TRUE for Print Setup, FALSE for Print Dialog
+ DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
+ HWND hWndParent = NULL)
+ : m_pd(m_pdActual)
+ {
+ memset(&m_pdActual, 0, sizeof(m_pdActual));
+
+ m_pd.lStructSize = sizeof(m_pdActual);
+ m_pd.hwndOwner = hWndParent;
+ m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);
+ m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc;
+ m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc;
+
+ if(bPrintSetupOnly)
+ m_pd.Flags |= PD_PRINTSETUP;
+ else
+ m_pd.Flags |= PD_RETURNDC;
+
+ m_pd.Flags &= ~PD_RETURNIC; // do not support information context
+ }
+
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0);
+ ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0);
+ ATLASSERT(m_pd.lpfnPrintHook != NULL); // can still be a user hook
+ ATLASSERT(m_pd.lpfnSetupHook != NULL); // can still be a user hook
+ ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this
+
+ if(m_pd.hwndOwner == NULL) // set only if not specified before
+ m_pd.hwndOwner = hWndParent;
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
+
+ BOOL bRet = ::PrintDlg(&m_pd);
+
+ m_hWnd = NULL;
+
+ return bRet ? IDOK : IDCANCEL;
+ }
+
+ // GetDefaults will not display a dialog but will get device defaults
+ BOOL GetDefaults()
+ {
+ m_pd.Flags |= PD_RETURNDEFAULT;
+ ATLASSERT(m_pd.hDevMode == NULL); // must be NULL
+ ATLASSERT(m_pd.hDevNames == NULL); // must be NULL
+
+ return ::PrintDlg(&m_pd);
+ }
+
+ // Helpers for parsing information after successful return num. copies requested
+ int GetCopies() const
+ {
+ if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0)
+ {
+ LPDEVMODE lpDevMode = GetDevMode();
+ return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
+ }
+
+ return m_pd.nCopies;
+ }
+
+ BOOL PrintCollate() const // TRUE if collate checked
+ {
+ return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintSelection() const // TRUE if printing selection
+ {
+ return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintAll() const // TRUE if printing all pages
+ {
+ return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
+ }
+
+ BOOL PrintRange() const // TRUE if printing page range
+ {
+ return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintToFile() const // TRUE if printing to a file
+ {
+ return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
+ }
+
+ int GetFromPage() const // starting page if valid
+ {
+ return PrintRange() ? m_pd.nFromPage : -1;
+ }
+
+ int GetToPage() const // ending page if valid
+ {
+ return PrintRange() ? m_pd.nToPage : -1;
+ }
+
+ LPDEVMODE GetDevMode() const // return DEVMODE
+ {
+ if(m_pd.hDevMode == NULL)
+ return NULL;
+
+ return (LPDEVMODE)::GlobalLock(m_pd.hDevMode);
+ }
+
+ LPCTSTR GetDriverName() const // return driver name
+ {
+ if(m_pd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wDriverOffset;
+ }
+
+ LPCTSTR GetDeviceName() const // return device name
+ {
+ if(m_pd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
+ }
+
+ LPCTSTR GetPortName() const // return output port name
+ {
+ if(m_pd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wOutputOffset;
+ }
+
+ HDC GetPrinterDC() const // return HDC (caller must delete)
+ {
+ ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0);
+ return m_pd.hDC;
+ }
+
+ // This helper creates a DC based on the DEVNAMES and DEVMODE structures.
+ // This DC is returned, but also stored in m_pd.hDC as though it had been
+ // returned by CommDlg. It is assumed that any previously obtained DC
+ // has been/will be deleted by the user. This may be
+ // used without ever invoking the print/print setup dialogs.
+ HDC CreatePrinterDC()
+ {
+ m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode);
+ return m_pd.hDC;
+ }
+
+// Implementation
+ PRINTDLG m_pdActual; // the Print/Print Setup need to share this
+
+ // The following handle the case of print setup... from the print dialog
+ CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit)
+ { }
+
+ BEGIN_MSG_MAP(CPrintDialogImpl)
+#ifdef psh1
+ COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed
+#else // !psh1
+ COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h
+#endif // !psh1
+ END_MSG_MAP()
+
+ LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
+ {
+ T dlgSetup(m_pd);
+ ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);
+ return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl);
+ }
+};
+
+class CPrintDialog : public CPrintDialogImpl<CPrintDialog>
+{
+public:
+ CPrintDialog(BOOL bPrintSetupOnly = FALSE,
+ DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
+ HWND hWndParent = NULL)
+ : CPrintDialogImpl<CPrintDialog>(bPrintSetupOnly, dwFlags, hWndParent)
+ { }
+
+ CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl<CPrintDialog>(pdInit)
+ { }
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrintDialogExImpl - new print dialog for Windows 2000
+
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+
+}; // namespace WTL
+
+#include <atlcom.h>
+
+extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
+extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
+
+namespace WTL
+{
+
+template <class T>
+class ATL_NO_VTABLE CPrintDialogExImpl :
+ public ATL::CWindow,
+ public ATL::CMessageMap,
+ public IPrintDialogCallback,
+ public ATL::IObjectWithSiteImpl< T >
+{
+public:
+ PRINTDLGEX m_pdex;
+
+// Constructor
+ CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
+ HWND hWndParent = NULL)
+ {
+ memset(&m_pdex, 0, sizeof(m_pdex));
+
+ m_pdex.lStructSize = sizeof(PRINTDLGEX);
+ m_pdex.hwndOwner = hWndParent;
+ m_pdex.Flags = dwFlags;
+ m_pdex.nStartPage = START_PAGE_GENERAL;
+ // callback object will be set in DoModal
+
+ m_pdex.Flags &= ~PD_RETURNIC; // do not support information context
+ }
+
+// Operations
+ HRESULT DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT(m_hWnd == NULL);
+ ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this
+
+ if(m_pdex.hwndOwner == NULL) // set only if not specified before
+ m_pdex.hwndOwner = hWndParent;
+
+ T* pT = static_cast<T*>(this);
+ m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT;
+
+ HRESULT hResult = ::PrintDlgEx(&m_pdex);
+
+ m_hWnd = NULL;
+
+ return hResult;
+ }
+
+ BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
+ return TRUE;
+ }
+
+ // GetDefaults will not display a dialog but will get device defaults
+ HRESULT GetDefaults()
+ {
+ m_pdex.Flags |= PD_RETURNDEFAULT;
+ ATLASSERT(m_pdex.hDevMode == NULL); // must be NULL
+ ATLASSERT(m_pdex.hDevNames == NULL); // must be NULL
+
+ return ::PrintDlgEx(&m_pdex);
+ }
+
+ // Helpers for parsing information after successful return num. copies requested
+ int GetCopies() const
+ {
+ if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0)
+ {
+ LPDEVMODE lpDevMode = GetDevMode();
+ return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
+ }
+
+ return m_pdex.nCopies;
+ }
+
+ BOOL PrintCollate() const // TRUE if collate checked
+ {
+ return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintSelection() const // TRUE if printing selection
+ {
+ return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintAll() const // TRUE if printing all pages
+ {
+ return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
+ }
+
+ BOOL PrintRange() const // TRUE if printing page range
+ {
+ return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL PrintToFile() const // TRUE if printing to a file
+ {
+ return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
+ }
+
+ LPDEVMODE GetDevMode() const // return DEVMODE
+ {
+ if(m_pdex.hDevMode == NULL)
+ return NULL;
+
+ return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode);
+ }
+
+ LPCTSTR GetDriverName() const // return driver name
+ {
+ if(m_pdex.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wDriverOffset;
+ }
+
+ LPCTSTR GetDeviceName() const // return device name
+ {
+ if(m_pdex.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
+ }
+
+ LPCTSTR GetPortName() const // return output port name
+ {
+ if(m_pdex.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
+ if(lpDev == NULL)
+ return NULL;
+
+ return (LPCTSTR)lpDev + lpDev->wOutputOffset;
+ }
+
+ HDC GetPrinterDC() const // return HDC (caller must delete)
+ {
+ ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0);
+ return m_pdex.hDC;
+ }
+
+ // This helper creates a DC based on the DEVNAMES and DEVMODE structures.
+ // This DC is returned, but also stored in m_pdex.hDC as though it had been
+ // returned by CommDlg. It is assumed that any previously obtained DC
+ // has been/will be deleted by the user. This may be
+ // used without ever invoking the print/print setup dialogs.
+ HDC CreatePrinterDC()
+ {
+ m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode);
+ return m_pdex.hDC;
+ }
+
+// Implementation - interfaces
+
+// IUnknown
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
+ {
+ if(ppvObject == NULL)
+ return E_POINTER;
+
+ T* pT = static_cast<T*>(this);
+ if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback))
+ {
+ *ppvObject = (IPrintDialogCallback*)pT;
+ // AddRef() not needed
+ return S_OK;
+ }
+ else if(IsEqualGUID(riid, IID_IObjectWithSite))
+ {
+ *ppvObject = (IObjectWithSite*)pT;
+ // AddRef() not needed
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return 1;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ return 1;
+ }
+
+// IPrintDialogCallback
+ STDMETHOD(InitDone)()
+ {
+ return S_FALSE;
+ }
+
+ STDMETHOD(SelectionChange)()
+ {
+ return S_FALSE;
+ }
+
+ STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
+ {
+ // set up m_hWnd the first time
+ if(m_hWnd == NULL)
+ Attach(hWnd);
+
+ // call message map
+ HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE;
+ if(hRet == S_OK && uMsg == WM_NOTIFY) // return in DWLP_MSGRESULT
+ ::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult);
+
+ if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE)
+ hRet = S_FALSE;
+
+ return hRet;
+ }
+};
+
+class CPrintDialogEx : public CPrintDialogExImpl<CPrintDialogEx>
+{
+public:
+ CPrintDialogEx(
+ DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
+ HWND hWndParent = NULL)
+ : CPrintDialogExImpl<CPrintDialogEx>(dwFlags, hWndParent)
+ { }
+
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPageSetupDialogImpl - Page Setup dialog
+
+#ifndef _WIN32_WCE
+
+template <class T>
+class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase
+{
+public:
+ PAGESETUPDLG m_psd;
+ ATL::CWndProcThunk m_thunkPaint;
+
+// Constructors
+ CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
+ {
+ memset(&m_psd, 0, sizeof(m_psd));
+
+ m_psd.lStructSize = sizeof(m_psd);
+ m_psd.hwndOwner = hWndParent;
+ m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK);
+ m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc;
+ m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this);
+#if (_ATL_VER >= 0x0700)
+ m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC();
+#else
+ m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk);
+#endif
+ }
+
+ DECLARE_EMPTY_MSG_MAP()
+
+// Attributes
+ LPDEVMODE GetDevMode() const // return DEVMODE
+ {
+ if(m_psd.hDevMode == NULL)
+ return NULL;
+
+ return (LPDEVMODE)::GlobalLock(m_psd.hDevMode);
+ }
+
+ LPCTSTR GetDriverName() const // return driver name
+ {
+ if(m_psd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
+ return (LPCTSTR)lpDev + lpDev->wDriverOffset;
+ }
+
+ LPCTSTR GetDeviceName() const // return device name
+ {
+ if(m_psd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
+ return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
+ }
+
+ LPCTSTR GetPortName() const // return output port name
+ {
+ if(m_psd.hDevNames == NULL)
+ return NULL;
+
+ LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
+ return (LPCTSTR)lpDev + lpDev->wOutputOffset;
+ }
+
+ HDC CreatePrinterDC()
+ {
+ return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode);
+ }
+
+ SIZE GetPaperSize() const
+ {
+ SIZE size;
+ size.cx = m_psd.ptPaperSize.x;
+ size.cy = m_psd.ptPaperSize.y;
+ return size;
+ }
+
+ void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const
+ {
+ if(lpRectMargins != NULL)
+ *lpRectMargins = m_psd.rtMargin;
+ if(lpRectMinMargins != NULL)
+ *lpRectMinMargins = m_psd.rtMinMargin;
+ }
+
+// Operations
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0);
+ ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0);
+ ATLASSERT(m_psd.lpfnPageSetupHook != NULL); // can still be a user hook
+ ATLASSERT(m_psd.lpfnPagePaintHook != NULL); // can still be a user hook
+
+ if(m_psd.hwndOwner == NULL) // set only if not specified before
+ m_psd.hwndOwner = hWndParent;
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
+
+ BOOL bRet = ::PageSetupDlg(&m_psd);
+
+ m_hWnd = NULL;
+
+ return bRet ? IDOK : IDCANCEL;
+ }
+
+// Implementation
+ static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ T* pT = (T*)hWnd;
+ UINT_PTR uRet = 0;
+ switch(uMsg)
+ {
+ case WM_PSD_PAGESETUPDLG:
+ uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam);
+ break;
+ case WM_PSD_FULLPAGERECT:
+ case WM_PSD_MINMARGINRECT:
+ case WM_PSD_MARGINRECT:
+ case WM_PSD_GREEKTEXTRECT:
+ case WM_PSD_ENVSTAMPRECT:
+ case WM_PSD_YAFULLPAGERECT:
+ uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam);
+ break;
+ default:
+ ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n"));
+ break;
+ }
+ return uRet;
+ }
+
+// Overridables
+ UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/)
+ {
+ // return 1 to prevent any more drawing
+ return 0;
+ }
+
+ UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/)
+ {
+ return 0; // do the default
+ }
+};
+
+class CPageSetupDialog : public CPageSetupDialogImpl<CPageSetupDialog>
+{
+public:
+ CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
+ : CPageSetupDialogImpl<CPageSetupDialog>(dwFlags, hWndParent)
+ { }
+
+ // override PaintHookProc and references to handlers
+ static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM)
+ {
+ return 0;
+ }
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFindReplaceDialogImpl - Find/FindReplace modeless dialogs
+
+#ifndef _WIN32_WCE
+
+template <class T>
+class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase
+{
+public:
+ enum { _cchFindReplaceBuffer = 128 };
+
+ FINDREPLACE m_fr;
+ TCHAR m_szFindWhat[_cchFindReplaceBuffer];
+ TCHAR m_szReplaceWith[_cchFindReplaceBuffer];
+
+// Constructors
+ CFindReplaceDialogImpl()
+ {
+ memset(&m_fr, 0, sizeof(m_fr));
+ m_szFindWhat[0] = _T('\0');
+ m_szReplaceWith[0] = _T('\0');
+
+ m_fr.lStructSize = sizeof(m_fr);
+ m_fr.Flags = FR_ENABLEHOOK;
+ m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc;
+ m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat;
+ m_fr.wFindWhatLen = _cchFindReplaceBuffer;
+ m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith;
+ m_fr.wReplaceWithLen = _cchFindReplaceBuffer;
+ }
+
+ // Note: You must allocate the object on the heap.
+ // If you do not, you must override OnFinalMessage()
+ virtual void OnFinalMessage(HWND /*hWnd*/)
+ {
+ delete this;
+ }
+
+ HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace
+ LPCTSTR lpszFindWhat,
+ LPCTSTR lpszReplaceWith = NULL,
+ DWORD dwFlags = FR_DOWN,
+ HWND hWndParent = NULL)
+ {
+ ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0);
+ ATLASSERT(m_fr.lpfnHook != NULL);
+
+ m_fr.Flags |= dwFlags;
+
+ if(hWndParent == NULL)
+ m_fr.hwndOwner = ::GetActiveWindow();
+ else
+ m_fr.hwndOwner = hWndParent;
+ ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog
+
+ if(lpszFindWhat != NULL)
+ SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE);
+
+ if(lpszReplaceWith != NULL)
+ SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE);
+
+ ATLASSERT(m_hWnd == NULL);
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
+
+ HWND hWnd = NULL;
+ if(bFindDialogOnly)
+ hWnd = ::FindText(&m_fr);
+ else
+ hWnd = ::ReplaceText(&m_fr);
+
+ ATLASSERT(m_hWnd == hWnd);
+ return hWnd;
+ }
+
+ static const UINT GetFindReplaceMsg()
+ {
+ static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
+ return nMsgFindReplace;
+ }
+ // call while handling FINDMSGSTRING registered message
+ // to retreive the object
+ static T* PASCAL GetNotifier(LPARAM lParam)
+ {
+ ATLASSERT(lParam != NULL);
+ T* pDlg = (T*)(lParam - offsetof(T, m_fr));
+ return pDlg;
+ }
+
+// Operations
+ // Helpers for parsing information after successful return
+ LPCTSTR GetFindString() const // get find string
+ {
+ return (LPCTSTR)m_fr.lpstrFindWhat;
+ }
+
+ LPCTSTR GetReplaceString() const // get replacement string
+ {
+ return (LPCTSTR)m_fr.lpstrReplaceWith;
+ }
+
+ BOOL SearchDown() const // TRUE if search down, FALSE is up
+ {
+ return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL FindNext() const // TRUE if command is find next
+ {
+ return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL MatchCase() const // TRUE if matching case
+ {
+ return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL MatchWholeWord() const // TRUE if matching whole words only
+ {
+ return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL ReplaceCurrent() const // TRUE if replacing current string
+ {
+ return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL ReplaceAll() const // TRUE if replacing all occurrences
+ {
+ return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE;
+ }
+
+ BOOL IsTerminating() const // TRUE if terminating dialog
+ {
+ return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ;
+ }
+};
+
+class CFindReplaceDialog : public CFindReplaceDialogImpl<CFindReplaceDialog>
+{
+public:
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+#endif // !_WIN32_WCE
+
+
+/////////////////////////////////////////////////////////////////////////
+// CDialogBaseUnits - Dialog Units helper
+//
+
+class CDialogBaseUnits
+{
+public:
+ SIZE m_sizeUnits;
+
+// Constructors
+ CDialogBaseUnits()
+ {
+ // The base units of the out-dated System Font
+ LONG nDlgBaseUnits = ::GetDialogBaseUnits();
+ m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
+ m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
+ }
+
+ CDialogBaseUnits(HWND hWnd)
+ {
+ if(!InitDialogBaseUnits(hWnd)) {
+ LONG nDlgBaseUnits = ::GetDialogBaseUnits();
+ m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
+ m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
+ }
+ }
+
+ CDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)
+ {
+ if(!InitDialogBaseUnits(hFont, hWnd)) {
+ LONG nDlgBaseUnits = ::GetDialogBaseUnits();
+ m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
+ m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
+ }
+ }
+
+ CDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)
+ {
+ if(!InitDialogBaseUnits(lf, hWnd)) {
+ LONG nDlgBaseUnits = ::GetDialogBaseUnits();
+ m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
+ m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
+ }
+ }
+
+// Operations
+ BOOL InitDialogBaseUnits(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(hWnd));
+ RECT rc = { 0, 0, 4, 8 };
+ if(!::MapDialogRect(hWnd, &rc)) return FALSE;
+ m_sizeUnits.cx = rc.right;
+ m_sizeUnits.cy = rc.bottom;
+ return TRUE;
+ }
+
+ BOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)
+ {
+ CFont font;
+ font.CreateFontIndirect(&lf);
+ if(font.IsNull()) return FALSE;
+ return InitDialogBaseUnits(font, hWnd);
+ }
+
+ BOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)
+ {
+ ATLASSERT(hFont != NULL);
+ CWindowDC dc = hWnd;
+ TEXTMETRIC tmText = { 0 };
+ SIZE sizeText = { 0 };
+ HFONT hFontOld = dc.SelectFont(hFont);
+ dc.GetTextMetrics(&tmText);
+ m_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading;
+ dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &sizeText);
+ m_sizeUnits.cx = (sizeText.cx + 26) / 52;
+ dc.SelectFont(hFontOld);
+ return TRUE;
+ }
+
+ SIZE GetDialogBaseUnits() const
+ {
+ return m_sizeUnits;
+ }
+
+ INT MapDialogPixelsX(INT x) const
+ {
+ return ::MulDiv(x, 4, m_sizeUnits.cx); // Pixels X to DLU
+ }
+
+ INT MapDialogPixelsY(INT y) const
+ {
+ return ::MulDiv(y, 8, m_sizeUnits.cy); // Pixels Y to DLU
+ }
+
+ POINT MapDialogPixels(POINT pt) const
+ {
+ POINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) };
+ return out;
+ }
+
+ SIZE MapDialogPixels(SIZE input) const
+ {
+ SIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) };
+ return out;
+ }
+
+ RECT MapDialogPixels(RECT input) const
+ {
+ RECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) };
+ return out;
+ }
+
+ INT MapDialogUnitsX(INT x) const
+ {
+ return ::MulDiv(x, m_sizeUnits.cx, 4); // DLU to Pixels X
+ }
+
+ INT MapDialogUnitsY(INT y) const
+ {
+ return ::MulDiv(y, m_sizeUnits.cx, 8); // DLU to Pixels Y
+ }
+
+ POINT MapDialogUnits(POINT pt) const
+ {
+ POINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) };
+ return out;
+ }
+
+ SIZE MapDialogUnits(SIZE input) const
+ {
+ SIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) };
+ return out;
+ }
+
+ RECT MapDialogUnits(RECT input) const
+ {
+ RECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) };
+ return out;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX
+
+#if (_ATL_VER >= 0x800)
+ typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX;
+ typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX;
+#else // (_ATL_VER >= 0x800)
+ typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX;
+ #pragma pack(push, 4)
+ struct DLGITEMTEMPLATEEX
+ {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+ };
+ #pragma pack(pop)
+#endif // (_ATL_VER >= 0x800)
+
+
+class CMemDlgTemplate
+{
+public:
+ enum StdCtrlType
+ {
+ CTRL_BUTTON = 0x0080,
+ CTRL_EDIT = 0x0081,
+ CTRL_STATIC = 0x0082,
+ CTRL_LISTBOX = 0x0083,
+ CTRL_SCROLLBAR = 0x0084,
+ CTRL_COMBOBOX = 0x0085
+ };
+
+ CMemDlgTemplate() : m_hData(NULL), m_pData(NULL), m_pPtr(NULL), m_cAllocated(0)
+ { }
+
+ ~CMemDlgTemplate()
+ {
+ Reset();
+ }
+
+ bool IsValid() const
+ {
+ return (m_pData != NULL);
+ }
+
+ bool IsTemplateEx() const
+ {
+ return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF);
+ }
+
+ LPDLGTEMPLATE GetTemplatePtr()
+ {
+ return reinterpret_cast<LPDLGTEMPLATE>(m_pData);
+ }
+
+ DLGTEMPLATEEX* GetTemplateExPtr()
+ {
+ return reinterpret_cast<DLGTEMPLATEEX*>(m_pData);
+ }
+
+ void Reset()
+ {
+ if (IsValid()) {
+#ifndef UNDER_CE
+ ::GlobalUnlock(m_pData);
+#endif
+ ATLVERIFY(::GlobalFree(m_hData) == NULL);
+ }
+
+ m_hData = NULL;
+ m_pData = NULL;
+ m_pPtr = NULL;
+ m_cAllocated = 0;
+ }
+
+ void Create(bool bDlgEx, LPCTSTR lpszCaption, RECT rc, DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,
+ ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)
+ {
+ Create(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,
+ lpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr);
+ }
+
+ void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,
+ ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)
+ {
+ // Should have DS_SETFONT style to set the dialog font name and size
+ if (lpstrFontName != NULL)
+ {
+ dwStyle |= DS_SETFONT;
+ }
+ else
+ {
+ dwStyle &= ~DS_SETFONT;
+ }
+
+ if (bDlgEx)
+ {
+ DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight};
+ AddData(&dlg, sizeof(dlg));
+ }
+ else
+ {
+ DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight};
+ AddData(&dlg, sizeof(dlg));
+ }
+
+#ifndef _WIN32_WCE
+ if (Menu.m_lpstr == NULL)
+ {
+ WORD menuData = 0;
+ AddData(&menuData, sizeof(WORD));
+ }
+ else if (IS_INTRESOURCE(Menu.m_lpstr))
+ {
+ WORD menuData[] = {0xFFFF, (WORD)Menu.m_lpstr};
+ AddData(menuData, sizeof(menuData));
+ }
+ else
+ {
+ AddString(Menu.m_lpstr);
+ }
+#else // _WIN32_WCE
+ // Windows CE doesn't support the addition of menus to a dialog box
+ ATLASSERT(Menu.m_lpstr == NULL);
+ Menu.m_lpstr; // avoid level 4 warning
+ WORD menuData = 0;
+ AddData(&menuData, sizeof(WORD));
+#endif // _WIN32_WCE
+
+ if (ClassName.m_lpstr == NULL)
+ {
+ WORD classData = 0;
+ AddData(&classData, sizeof(WORD));
+ }
+ else if (IS_INTRESOURCE(ClassName.m_lpstr))
+ {
+ WORD classData[] = {0xFFFF, (WORD)ClassName.m_lpstr};
+ AddData(classData, sizeof(classData));
+ }
+ else
+ {
+ AddString(ClassName.m_lpstr);
+ }
+
+ // Set dialog caption
+ AddString(lpszCaption);
+
+ if (lpstrFontName != NULL)
+ {
+ AddData(&wFontSize, sizeof(wFontSize));
+
+ if (bDlgEx)
+ {
+ AddData(&wWeight, sizeof(wWeight));
+ AddData(&bItalic, sizeof(bItalic));
+ AddData(&bCharset, sizeof(bCharset));
+ }
+
+ AddString(lpstrFontName);
+ }
+ }
+
+ void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, RECT rc, DWORD dwStyle, DWORD dwExStyle,
+ ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
+ {
+ AddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,
+ Text.m_lpstr, pCreationData, nCreationData, dwHelpID);
+ }
+
+ void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle,
+ ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
+ {
+ ATLASSERT(IsValid());
+
+ // DWORD align data
+ m_pPtr = (LPBYTE)(DWORD_PTR)((DWORD)(DWORD_PTR)(m_pPtr + 3) & (~3));
+
+ if (IsTemplateEx())
+ {
+ DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData;
+ dlg->cDlgItems++;
+
+ DLGITEMTEMPLATEEX item = {dwHelpID, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId};
+ AddData(&item, sizeof(item));
+ }
+ else
+ {
+ LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData;
+ dlg->cdit++;
+
+ DLGITEMTEMPLATE item = {ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId};
+ AddData(&item, sizeof(item));
+ }
+
+ ATLASSERT(ClassName.m_lpstr != NULL);
+ if (IS_INTRESOURCE(ClassName.m_lpstr))
+ {
+ WORD wData[] = {0xFFFF, (WORD)ClassName.m_lpstr};
+ AddData(wData, sizeof(wData));
+ }
+ else
+ {
+ AddString(ClassName.m_lpstr);
+ }
+
+ if (Text.m_lpstr == NULL)
+ {
+ WORD classData = 0;
+ AddData(&classData, sizeof(WORD));
+ }
+ else if (IS_INTRESOURCE(Text.m_lpstr))
+ {
+ WORD wData[] = {0xFFFF, (WORD)Text.m_lpstr};
+ AddData(wData, sizeof(wData));
+ }
+ else
+ {
+ AddString(Text.m_lpstr);
+ }
+
+ AddData(&nCreationData, sizeof(nCreationData));
+
+ if ((nCreationData != 0))
+ {
+ ATLASSERT(pCreationData != NULL);
+ AddData(pCreationData, nCreationData * sizeof(WORD));
+ }
+ }
+
+ void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight,
+ DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
+ {
+ AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID);
+ }
+
+ void AddData(LPCVOID pData, size_t nData)
+ {
+ ATLASSERT(pData != NULL);
+
+ const SIZE_T ALLOCATION_INCREMENT = 1024;
+
+ if (m_pData == NULL)
+ {
+ m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
+ m_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated);
+ ATLASSERT(m_hData != NULL);
+#ifndef UNDER_CE
+ m_pPtr = m_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));
+#else
+ m_pPtr = m_pData = static_cast<LPBYTE>(m_hData);
+#endif
+ ATLASSERT(m_pData != NULL);
+ }
+ else if (((m_pPtr - m_pData) + nData) > m_cAllocated)
+ {
+ SIZE_T ptrPos = (m_pPtr - m_pData);
+ m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
+#ifndef UNDER_CE
+ ::GlobalUnlock(m_pData);
+#endif
+ m_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT);
+ ATLASSERT(m_hData != NULL);
+#ifndef UNDER_CE
+ m_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));
+#else
+ m_pData = static_cast<LPBYTE>(m_hData);
+#endif
+ ATLASSERT(m_pData != NULL);
+ m_pPtr = m_pData + ptrPos;
+ }
+
+ SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData);
+
+ m_pPtr += nData;
+ }
+
+ void AddString(LPCTSTR lpszStr)
+ {
+ if (lpszStr == NULL)
+ {
+ WCHAR szEmpty = 0;
+ AddData(&szEmpty, sizeof(szEmpty));
+ }
+ else
+ {
+ USES_CONVERSION;
+ LPCWSTR lpstr = T2CW(lpszStr);
+ int nSize = lstrlenW(lpstr) + 1;
+ AddData(lpstr, nSize * sizeof(WCHAR));
+ }
+ }
+
+ HANDLE m_hData;
+ LPBYTE m_pData;
+ LPBYTE m_pPtr;
+ SIZE_T m_cAllocated;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Dialog and control macros for indirect dialogs
+
+// for DLGTEMPLATE
+#define BEGIN_DIALOG(x, y, width, height) \
+ void DoInitTemplate() \
+ { \
+ bool bExTemplate = false; \
+ short nX = x, nY = y, nWidth = width, nHeight = height; \
+ LPCTSTR szCaption = NULL; \
+ DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
+ DWORD dwExStyle = 0; \
+ LPCTSTR szFontName = NULL; \
+ WORD wFontSize = 0; \
+ WORD wWeight = 0; \
+ BYTE bItalic = 0; \
+ BYTE bCharset = 0; \
+ DWORD dwHelpID = 0; \
+ ATL::_U_STRINGorID Menu = 0U; \
+ ATL::_U_STRINGorID ClassName = 0U;
+
+// for DLGTEMPLATEEX
+#define BEGIN_DIALOG_EX(x, y, width, height, helpID) \
+ void DoInitTemplate() \
+ { \
+ bool bExTemplate = true; \
+ short nX = x, nY = y, nWidth = width, nHeight = height; \
+ LPCTSTR szCaption = NULL; \
+ DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
+ DWORD dwExStyle = 0; \
+ LPCTSTR szFontName = NULL; \
+ WORD wFontSize = 0; \
+ WORD wWeight = 0; \
+ BYTE bItalic = 0; \
+ BYTE bCharset = 0; \
+ DWORD dwHelpID = helpID; \
+ ATL::_U_STRINGorID Menu = 0U; \
+ ATL::_U_STRINGorID ClassName = 0U;
+
+#define END_DIALOG() \
+ m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \
+ };
+
+#define DIALOG_CAPTION(caption) \
+ szCaption = caption;
+#define DIALOG_STYLE(style) \
+ dwStyle = style;
+#define DIALOG_EXSTYLE(exStyle) \
+ dwExStyle = exStyle;
+#define DIALOG_FONT(pointSize, typeFace) \
+ wFontSize = pointSize; \
+ szFontName = typeFace;
+#define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \
+ ATLASSERT(bExTemplate); \
+ wFontSize = pointsize; \
+ szFontName = typeface; \
+ wWeight = weight; \
+ bItalic = italic; \
+ bCharset = charset;
+#define DIALOG_MENU(menuName) \
+ Menu = menuName;
+#define DIALOG_CLASS(className) \
+ ClassName = className;
+
+#define BEGIN_CONTROLS_MAP() \
+ void DoInitControls() \
+ {
+
+#define END_CONTROLS_MAP() \
+ };
+
+
+#define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0);
+#define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0);
+#define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0);
+#define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
+#ifndef _WIN32_WCE
+#define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0);
+#endif // !_WIN32_WCE
+#define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
+#define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
+#define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
+#define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0);
+#define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0);
+#define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0);
+#define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \
+ m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0);
+#define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \
+ m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0);
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CIndirectDialogImpl - dialogs with template in memory
+
+template <class T, class TDlgTemplate = CMemDlgTemplate, class TBase = ATL::CDialogImpl<T, ATL::CWindow> >
+class ATL_NO_VTABLE CIndirectDialogImpl : public TBase
+{
+public:
+ enum { IDD = 0 }; // no dialog template resource
+
+ TDlgTemplate m_Template;
+
+ void CreateTemplate()
+ {
+ T* pT = static_cast<T*>(this);
+ pT->DoInitTemplate();
+ pT->DoInitControls();
+ }
+
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_hWnd == NULL);
+
+ if (!m_Template.IsValid())
+ CreateTemplate();
+
+#if (_ATL_VER >= 0x0800)
+ // Allocate the thunk structure here, where we can fail gracefully.
+ BOOL result = m_thunk.Init(NULL, NULL);
+ if (result == FALSE)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+#endif // (_ATL_VER >= 0x0800)
+
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, pT);
+
+#ifdef _DEBUG
+ m_bModal = true;
+#endif // _DEBUG
+
+ return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
+ }
+
+ HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->m_hWnd == NULL);
+
+ if (!m_Template.IsValid())
+ CreateTemplate();
+
+#if (_ATL_VER >= 0x0800)
+ // Allocate the thunk structure here, where we can fail gracefully.
+ BOOL result = m_thunk.Init(NULL, NULL);
+ if (result == FALSE)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return NULL;
+ }
+#endif // (_ATL_VER >= 0x0800)
+
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, pT);
+
+#ifdef _DEBUG
+ m_bModal = false;
+#endif // _DEBUG
+
+ HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
+ ATLASSERT(m_hWnd == hWnd);
+
+ return hWnd;
+ }
+
+ // for CComControl
+ HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)
+ {
+ return Create(hWndParent, dwInitParam);
+ }
+
+ void DoInitTemplate()
+ {
+ ATLASSERT(FALSE); // MUST be defined in derived class
+ }
+
+ void DoInitControls()
+ {
+ ATLASSERT(FALSE); // MUST be defined in derived class
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CPropertySheetWindow - client side for a property sheet
+
+class CPropertySheetWindow : public ATL::CWindow
+{
+public:
+// Constructors
+ CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
+ { }
+
+ CPropertySheetWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ int GetPageCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HWND hWndTabCtrl = GetTabControl();
+ ATLASSERT(hWndTabCtrl != NULL);
+ return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);
+ }
+
+ HWND GetActivePage() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);
+ }
+
+ int GetActiveIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ HWND hWndTabCtrl = GetTabControl();
+ ATLASSERT(hWndTabCtrl != NULL);
+ return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);
+ }
+
+ BOOL SetActivePage(int nPageIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L);
+ }
+
+ BOOL SetActivePage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hPage != NULL);
+ return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage);
+ }
+
+ BOOL SetActivePageByID(int nPageID)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID);
+ }
+
+ void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
+ ATLASSERT(lpszText != NULL);
+ ::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText);
+ }
+
+ HWND GetTabControl() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);
+ }
+
+ void SetFinishText(LPCTSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);
+ }
+
+ void SetWizardButtons(DWORD dwFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);
+ }
+
+// Operations
+ BOOL AddPage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hPage != NULL);
+ return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
+ }
+
+ BOOL AddPage(LPCPROPSHEETPAGE pPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pPage != NULL);
+ HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
+ if(hPage == NULL)
+ return FALSE;
+ return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hPage != NULL);
+ return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
+ }
+
+ BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pPage != NULL);
+ HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
+ if(hPage == NULL)
+ return FALSE;
+ return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
+ }
+
+ BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hPage != NULL);
+ return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
+ }
+
+ BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pPage != NULL);
+ HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
+ if(hPage == NULL)
+ return FALSE;
+ return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
+ }
+#endif // !_WIN32_WCE
+
+ void RemovePage(int nPageIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L);
+ }
+
+ void RemovePage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(hPage != NULL);
+ ::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage);
+ }
+
+ BOOL PressButton(int nButton)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);
+ }
+
+ BOOL Apply()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L);
+ }
+
+ void CancelToClose()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L);
+ }
+
+ void SetModified(HWND hWndPage, BOOL bChanged = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(::IsWindow(hWndPage));
+ UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED;
+ ::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L);
+ }
+
+ LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam);
+ }
+
+ void RebootSystem()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L);
+ }
+
+ void RestartWindows()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L);
+ }
+
+ BOOL IsDialogMessage(LPMSG lpMsg)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg);
+ }
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ int HwndToIndex(HWND hWnd) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L);
+ }
+
+ HWND IndexToHwnd(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L);
+ }
+
+ int PageToIndex(HPROPSHEETPAGE hPage) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage);
+ }
+
+ HPROPSHEETPAGE IndexToPage(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L);
+ }
+
+ int IdToIndex(int nID) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID);
+ }
+
+ int IndexToId(int nIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L);
+ }
+
+ int GetResult() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L);
+ }
+
+ BOOL RecalcPageSizes()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L);
+ }
+
+ void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle);
+ }
+
+ void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+// Implementation - override to prevent usage
+ HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
+ {
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CPropertySheetImpl - implements a property sheet
+
+template <class T, class TBase = CPropertySheetWindow>
+class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase >
+{
+public:
+ PROPSHEETHEADER m_psh;
+ ATL::CSimpleArray<HPROPSHEETPAGE> m_arrPages;
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
+ #ifndef PROPSHEET_LINK_SIZE
+ #define PROPSHEET_LINK_SIZE 128
+ #endif // PROPSHEET_LINK_SIZE
+ TCHAR m_szLink[PROPSHEET_LINK_SIZE];
+ static LPCTSTR m_pszTitle;
+ static LPCTSTR m_pszLink;
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+
+// Construction/Destruction
+ CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
+ {
+ memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
+ m_psh.dwSize = sizeof(PROPSHEETHEADER);
+ m_psh.dwFlags = PSH_USECALLBACK;
+ m_psh.hInstance = ModuleHelper::GetResourceInstance();
+ m_psh.phpage = NULL; // will be set later
+ m_psh.nPages = 0; // will be set later
+ m_psh.pszCaption = title.m_lpstr;
+ m_psh.nStartPage = uStartPage;
+ m_psh.hwndParent = hWndParent; // if NULL, will be set in DoModal/Create
+ m_psh.pfnCallback = T::PropSheetCallback;
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
+ m_psh.dwFlags |= PSH_MAXIMIZE;
+ m_szLink[0] = 0;
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+ }
+
+ ~CPropertySheetImpl()
+ {
+ if(m_arrPages.GetSize() > 0) // sheet never created, destroy all pages
+ {
+ for(int i = 0; i < m_arrPages.GetSize(); i++)
+ ::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]);
+ }
+ }
+
+// Callback function and overrideables
+ static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
+ {
+ lParam; // avoid level 4 warning
+ int nRet = 0;
+
+ if(uMsg == PSCB_INITIALIZED)
+ {
+ ATLASSERT(hWnd != NULL);
+ T* pT = (T*)ModuleHelper::ExtractCreateWndData();
+ // subclass the sheet window
+ pT->SubclassWindow(hWnd);
+ // remove page handles array
+ pT->_CleanUpPages();
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
+ m_pszTitle = pT->m_psh.pszCaption;
+ if(*pT->m_szLink != 0)
+ m_pszLink = pT->m_szLink;
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
+
+ pT->OnSheetInitialized();
+ }
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg
+ else
+ {
+ switch(uMsg)
+ {
+ case PSCB_GETVERSION :
+ nRet = COMCTL32_VERSION;
+ break;
+ case PSCB_GETTITLE :
+ if(m_pszTitle != NULL)
+ {
+ lstrcpy((LPTSTR)lParam, m_pszTitle);
+ m_pszTitle = NULL;
+ }
+ break;
+ case PSCB_GETLINKTEXT:
+ if(m_pszLink != NULL)
+ {
+ lstrcpy((LPTSTR)lParam, m_pszLink);
+ m_pszLink = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+
+ return nRet;
+ }
+
+ void OnSheetInitialized()
+ {
+ }
+
+// Create method
+ HWND Create(HWND hWndParent = NULL)
+ {
+ ATLASSERT(m_hWnd == NULL);
+
+ m_psh.dwFlags |= PSH_MODELESS;
+ if(m_psh.hwndParent == NULL)
+ m_psh.hwndParent = hWndParent;
+ m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
+ m_psh.nPages = m_arrPages.GetSize();
+
+ T* pT = static_cast<T*>(this);
+ ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
+
+ HWND hWnd = (HWND)::PropertySheet(&m_psh);
+ _CleanUpPages(); // ensure clean-up, required if call failed
+
+ ATLASSERT(m_hWnd == hWnd);
+
+ return hWnd;
+ }
+
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
+ {
+ ATLASSERT(m_hWnd == NULL);
+
+ m_psh.dwFlags &= ~PSH_MODELESS;
+ if(m_psh.hwndParent == NULL)
+ m_psh.hwndParent = hWndParent;
+ m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
+ m_psh.nPages = m_arrPages.GetSize();
+
+ T* pT = static_cast<T*>(this);
+ ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
+
+ INT_PTR nRet = ::PropertySheet(&m_psh);
+ _CleanUpPages(); // ensure clean-up, required if call failed
+
+ return nRet;
+ }
+
+ // implementation helper - clean up pages array
+ void _CleanUpPages()
+ {
+ m_psh.nPages = 0;
+ m_psh.phpage = NULL;
+ m_arrPages.RemoveAll();
+ }
+
+// Attributes (extended overrides of client class methods)
+// These now can be called before the sheet is created
+// Note: Calling these after the sheet is created gives unpredictable results
+ int GetPageCount() const
+ {
+ if(m_hWnd == NULL) // not created yet
+ return m_arrPages.GetSize();
+ return TBase::GetPageCount();
+ }
+
+ int GetActiveIndex() const
+ {
+ if(m_hWnd == NULL) // not created yet
+ return m_psh.nStartPage;
+ return TBase::GetActiveIndex();
+ }
+
+ HPROPSHEETPAGE GetPage(int nPageIndex) const
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ return (HPROPSHEETPAGE)m_arrPages[nPageIndex];
+ }
+
+ int GetPageIndex(HPROPSHEETPAGE hPage) const
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ return m_arrPages.Find((HPROPSHEETPAGE&)hPage);
+ }
+
+ BOOL SetActivePage(int nPageIndex)
+ {
+ if(m_hWnd == NULL) // not created yet
+ {
+ ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize());
+ m_psh.nStartPage = nPageIndex;
+ return TRUE;
+ }
+ return TBase::SetActivePage(nPageIndex);
+ }
+
+ BOOL SetActivePage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(hPage != NULL);
+ if (m_hWnd == NULL) // not created yet
+ {
+ int nPageIndex = GetPageIndex(hPage);
+ if(nPageIndex == -1)
+ return FALSE;
+
+ return SetActivePage(nPageIndex);
+ }
+ return TBase::SetActivePage(hPage);
+
+ }
+
+ void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
+ {
+ ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
+ ATLASSERT(lpszText != NULL);
+
+ if(m_hWnd == NULL)
+ {
+ // set internal state
+ m_psh.pszCaption = lpszText; // must exist until sheet is created
+ m_psh.dwFlags &= ~PSH_PROPTITLE;
+ m_psh.dwFlags |= nStyle;
+ }
+ else
+ {
+ // set external state
+ TBase::SetTitle(lpszText, nStyle);
+ }
+ }
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field
+ void SetLinkText(LPCTSTR lpszText)
+ {
+ ATLASSERT(lpszText != NULL);
+ ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE);
+ lstrcpy(m_szLink, lpszText);
+ }
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+
+ void SetWizardMode()
+ {
+ m_psh.dwFlags |= PSH_WIZARD;
+ }
+
+ void EnableHelp()
+ {
+ m_psh.dwFlags |= PSH_HASHELP;
+ }
+
+// Operations
+ BOOL AddPage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(hPage != NULL);
+ BOOL bRet = FALSE;
+ if(m_hWnd != NULL)
+ bRet = TBase::AddPage(hPage);
+ else // sheet not created yet, use internal data
+ bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage);
+ return bRet;
+ }
+
+ BOOL AddPage(LPCPROPSHEETPAGE pPage)
+ {
+ ATLASSERT(pPage != NULL);
+ HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
+ if(hPage == NULL)
+ return FALSE;
+ BOOL bRet = AddPage(hPage);
+ if(!bRet)
+ ::DestroyPropertySheetPage(hPage);
+ return bRet;
+ }
+
+ BOOL RemovePage(HPROPSHEETPAGE hPage)
+ {
+ ATLASSERT(hPage != NULL);
+ if (m_hWnd == NULL) // not created yet
+ {
+ int nPage = GetPageIndex(hPage);
+ if(nPage == -1)
+ return FALSE;
+ return RemovePage(nPage);
+ }
+ TBase::RemovePage(hPage);
+ return TRUE;
+
+ }
+
+ BOOL RemovePage(int nPageIndex)
+ {
+ BOOL bRet = TRUE;
+ if(m_hWnd != NULL)
+ TBase::RemovePage(nPageIndex);
+ else // sheet not created yet, use internal data
+ bRet = m_arrPages.RemoveAt(nPageIndex);
+ return bRet;
+ }
+
+#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+ void SetHeader(LPCTSTR szbmHeader)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+
+ m_psh.dwFlags &= ~PSH_WIZARD;
+ m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97);
+ m_psh.pszbmHeader = szbmHeader;
+ }
+
+ void SetHeader(HBITMAP hbmHeader)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+
+ m_psh.dwFlags &= ~PSH_WIZARD;
+ m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97);
+ m_psh.hbmHeader = hbmHeader;
+ }
+
+ void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+
+ m_psh.dwFlags &= ~PSH_WIZARD;
+ m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97;
+ m_psh.pszbmWatermark = szbmWatermark;
+
+ if (hplWatermark != NULL)
+ {
+ m_psh.dwFlags |= PSH_USEHPLWATERMARK;
+ m_psh.hplWatermark = hplWatermark;
+ }
+ }
+
+ void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+
+ m_psh.dwFlags &= ~PSH_WIZARD;
+ m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97);
+ m_psh.hbmWatermark = hbmWatermark;
+
+ if (hplWatermark != NULL)
+ {
+ m_psh.dwFlags |= PSH_USEHPLWATERMARK;
+ m_psh.hplWatermark = hplWatermark;
+ }
+ }
+
+ void StretchWatermark(bool bStretchWatermark)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ if (bStretchWatermark)
+ m_psh.dwFlags |= PSH_STRETCHWATERMARK;
+ else
+ m_psh.dwFlags &= ~PSH_STRETCHWATERMARK;
+ }
+#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CPropertySheetImpl)
+ MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+ MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
+ END_MSG_MAP()
+
+ LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
+ if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) &&
+ ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))
+ DestroyWindow();
+ return lRet;
+ }
+
+ LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE))
+ SendMessage(WM_CLOSE);
+ else
+ bHandled = FALSE;
+ return 0;
+ }
+};
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers
+template < class T, class TBase >
+LPCWSTR CPropertySheetImpl<T,TBase>::m_pszTitle = NULL;
+template < class T, class TBase>
+LPCWSTR CPropertySheetImpl<T,TBase>::m_pszLink = NULL;
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+
+// for non-customized sheets
+class CPropertySheet : public CPropertySheetImpl<CPropertySheet>
+{
+public:
+ CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
+ : CPropertySheetImpl<CPropertySheet>(title, uStartPage, hWndParent)
+ { }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPropertyPageWindow - client side for a property page
+
+class CPropertyPageWindow : public ATL::CWindow
+{
+public:
+// Constructors
+ CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
+ { }
+
+ CPropertyPageWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ CPropertySheetWindow GetPropertySheet() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CPropertySheetWindow(GetParent());
+ }
+
+// Operations
+ BOOL Apply()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ return GetPropertySheet().Apply();
+ }
+
+ void CancelToClose()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetPropertySheet().CancelToClose();
+ }
+
+ void SetModified(BOOL bChanged = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetPropertySheet().SetModified(m_hWnd, bChanged);
+ }
+
+ LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ return GetPropertySheet().QuerySiblings(wParam, lParam);
+ }
+
+ void RebootSystem()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetPropertySheet().RebootSystem();
+ }
+
+ void RestartWindows()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetPropertySheet().RestartWindows();
+ }
+
+ void SetWizardButtons(DWORD dwFlags)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetPropertySheet().SetWizardButtons(dwFlags);
+ }
+
+// Implementation - overrides to prevent usage
+ HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
+ {
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CPropertyPageImpl - implements a property page
+
+template <class T, class TBase = CPropertyPageWindow>
+class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase >
+{
+public:
+ PROPSHEETPAGE m_psp;
+
+ operator PROPSHEETPAGE*() { return &m_psp; }
+
+// Construction
+ CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
+ {
+ // initialize PROPSHEETPAGE struct
+ memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
+ m_psp.dwSize = sizeof(PROPSHEETPAGE);
+ m_psp.dwFlags = PSP_USECALLBACK;
+ m_psp.hInstance = ModuleHelper::GetResourceInstance();
+ T* pT = static_cast<T*>(this);
+ m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD);
+ m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;
+ m_psp.pfnCallback = T::PropPageCallback;
+ m_psp.lParam = (LPARAM)pT;
+
+ if(title.m_lpstr != NULL)
+ SetTitle(title);
+ }
+
+// Callback function and overrideables
+ static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
+ {
+ hWnd; // avoid level 4 warning
+ ATLASSERT(hWnd == NULL);
+ T* pT = (T*)ppsp->lParam;
+ UINT uRet = 0;
+
+ switch(uMsg)
+ {
+ case PSPCB_CREATE:
+ {
+ ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT;
+ ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage);
+ uRet = pT->OnPageCreate() ? 1 : 0;
+ }
+ break;
+#if (_WIN32_IE >= 0x0500)
+ case PSPCB_ADDREF:
+ pT->OnPageAddRef();
+ break;
+#endif // (_WIN32_IE >= 0x0500)
+ case PSPCB_RELEASE:
+ pT->OnPageRelease();
+ break;
+ default:
+ break;
+ }
+
+ return uRet;
+ }
+
+ bool OnPageCreate()
+ {
+ return true; // true - allow page to be created, false - prevent creation
+ }
+
+#if (_WIN32_IE >= 0x0500)
+ void OnPageAddRef()
+ {
+ }
+#endif // (_WIN32_IE >= 0x0500)
+
+ void OnPageRelease()
+ {
+ }
+
+// Create method
+ HPROPSHEETPAGE Create()
+ {
+ return ::CreatePropertySheetPage(&m_psp);
+ }
+
+// Attributes
+ void SetTitle(ATL::_U_STRINGorID title)
+ {
+ m_psp.pszTitle = title.m_lpstr;
+ m_psp.dwFlags |= PSP_USETITLE;
+ }
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ m_psp.dwFlags |= PSP_USEHEADERTITLE;
+ m_psp.pszHeaderTitle = lpstrHeaderTitle;
+ }
+
+ void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ m_psp.dwFlags |= PSP_USEHEADERSUBTITLE;
+ m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle;
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+// Operations
+ void EnableHelp()
+ {
+ m_psp.dwFlags |= PSP_HASHELP;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CPropertyPageImpl)
+ MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+ END_MSG_MAP()
+
+ // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
+ // handlers that return direct values without any restrictions
+ LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+#ifndef _WIN32_WCE
+ // This notification is sometimes received on Windows CE after the window is already destroyed
+ ATLASSERT(::IsWindow(m_hWnd));
+#endif
+ NMHDR* pNMHDR = (NMHDR*)lParam;
+
+ // don't handle messages not from the page/sheet itself
+ if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+#ifdef _WIN32_WCE
+ ATLASSERT(::IsWindow(m_hWnd));
+#endif
+
+ T* pT = static_cast<T*>(this);
+ LRESULT lResult = 0;
+ switch(pNMHDR->code)
+ {
+#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
+ case PSN_SETACTIVE:
+ lResult = pT->OnSetActive();
+ break;
+ case PSN_KILLACTIVE:
+ lResult = pT->OnKillActive();
+ break;
+ case PSN_APPLY:
+ lResult = pT->OnApply();
+ break;
+ case PSN_RESET:
+ pT->OnReset();
+ break;
+ case PSN_QUERYCANCEL:
+ lResult = pT->OnQueryCancel();
+ break;
+ case PSN_WIZNEXT:
+ lResult = pT->OnWizardNext();
+ break;
+ case PSN_WIZBACK:
+ lResult = pT->OnWizardBack();
+ break;
+ case PSN_WIZFINISH:
+ lResult = pT->OnWizardFinish();
+ break;
+ case PSN_HELP:
+ pT->OnHelp();
+ break;
+#ifndef _WIN32_WCE
+#if (_WIN32_IE >= 0x0400)
+ case PSN_GETOBJECT:
+ if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
+ bHandled = FALSE;
+ break;
+#endif // (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0500)
+ case PSN_TRANSLATEACCELERATOR:
+ {
+ LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
+ lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam);
+ }
+ break;
+ case PSN_QUERYINITIALFOCUS:
+ {
+ LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
+ lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
+ }
+ break;
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_WIN32_WCE
+
+#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+ case PSN_SETACTIVE:
+ lResult = pT->OnSetActive() ? 0 : -1;
+ break;
+ case PSN_KILLACTIVE:
+ lResult = !pT->OnKillActive();
+ break;
+ case PSN_APPLY:
+ lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
+ break;
+ case PSN_RESET:
+ pT->OnReset();
+ break;
+ case PSN_QUERYCANCEL:
+ lResult = !pT->OnQueryCancel();
+ break;
+ case PSN_WIZNEXT:
+ lResult = pT->OnWizardNext();
+ break;
+ case PSN_WIZBACK:
+ lResult = pT->OnWizardBack();
+ break;
+ case PSN_WIZFINISH:
+ lResult = !pT->OnWizardFinish();
+ break;
+ case PSN_HELP:
+ pT->OnHelp();
+ break;
+#ifndef _WIN32_WCE
+#if (_WIN32_IE >= 0x0400)
+ case PSN_GETOBJECT:
+ if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
+ bHandled = FALSE;
+ break;
+#endif // (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0500)
+ case PSN_TRANSLATEACCELERATOR:
+ {
+ LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
+ lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
+ }
+ break;
+ case PSN_QUERYINITIALFOCUS:
+ {
+ LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
+ lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
+ }
+ break;
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_WIN32_WCE
+
+#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+ default:
+ bHandled = FALSE; // not handled
+ }
+
+ return lResult;
+ }
+
+// Overridables
+ // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
+ // handlers that return direct values without any restrictions
+#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
+ int OnSetActive()
+ {
+ // 0 = allow activate
+ // -1 = go back that was active
+ // page ID = jump to page
+ return 0;
+ }
+
+ BOOL OnKillActive()
+ {
+ // FALSE = allow deactivate
+ // TRUE = prevent deactivation
+ return FALSE;
+ }
+
+ int OnApply()
+ {
+ // PSNRET_NOERROR = apply OK
+ // PSNRET_INVALID = apply not OK, return to this page
+ // PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus
+ return PSNRET_NOERROR;
+ }
+
+ void OnReset()
+ {
+ }
+
+ BOOL OnQueryCancel()
+ {
+ // FALSE = allow cancel
+ // TRUE = prevent cancel
+ return FALSE;
+ }
+
+ int OnWizardBack()
+ {
+ // 0 = goto previous page
+ // -1 = prevent page change
+ // >0 = jump to page by dlg ID
+ return 0;
+ }
+
+ int OnWizardNext()
+ {
+ // 0 = goto next page
+ // -1 = prevent page change
+ // >0 = jump to page by dlg ID
+ return 0;
+ }
+
+ INT_PTR OnWizardFinish()
+ {
+ // FALSE = allow finish
+ // TRUE = prevent finish
+ // HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only)
+ return FALSE;
+ }
+
+ void OnHelp()
+ {
+ }
+
+#ifndef _WIN32_WCE
+#if (_WIN32_IE >= 0x0400)
+ BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
+ {
+ return FALSE; // not processed
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500)
+ int OnTranslateAccelerator(LPMSG /*lpMsg*/)
+ {
+ // PSNRET_NOERROR - message not handled
+ // PSNRET_MESSAGEHANDLED - message handled
+ return PSNRET_NOERROR;
+ }
+
+ HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
+ {
+ // NULL = set focus to default control
+ // HWND = set focus to HWND
+ return NULL;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_WIN32_WCE
+
+#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+ BOOL OnSetActive()
+ {
+ return TRUE;
+ }
+
+ BOOL OnKillActive()
+ {
+ return TRUE;
+ }
+
+ BOOL OnApply()
+ {
+ return TRUE;
+ }
+
+ void OnReset()
+ {
+ }
+
+ BOOL OnQueryCancel()
+ {
+ return TRUE; // ok to cancel
+ }
+
+ int OnWizardBack()
+ {
+ // 0 = goto previous page
+ // -1 = prevent page change
+ // >0 = jump to page by dlg ID
+ return 0;
+ }
+
+ int OnWizardNext()
+ {
+ // 0 = goto next page
+ // -1 = prevent page change
+ // >0 = jump to page by dlg ID
+ return 0;
+ }
+
+ BOOL OnWizardFinish()
+ {
+ return TRUE;
+ }
+
+ void OnHelp()
+ {
+ }
+
+#ifndef _WIN32_WCE
+#if (_WIN32_IE >= 0x0400)
+ BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
+ {
+ return FALSE; // not processed
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500)
+ BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/)
+ {
+ return FALSE; // not translated
+ }
+
+ HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
+ {
+ return NULL; // default
+ }
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_WIN32_WCE
+
+#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+};
+
+// for non-customized pages
+template <WORD t_wDlgTemplateID>
+class CPropertyPage : public CPropertyPageImpl<CPropertyPage<t_wDlgTemplateID> >
+{
+public:
+ enum { IDD = t_wDlgTemplateID };
+
+ CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<CPropertyPage>(title)
+ { }
+
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CAxPropertyPageImpl - property page that hosts ActiveX controls
+
+#ifndef _ATL_NO_HOSTING
+
+// Note: You must #include <atlhost.h> to use these classes
+
+template <class T, class TBase = CPropertyPageWindow>
+class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase >
+{
+public:
+// Data members
+ HGLOBAL m_hInitData;
+ HGLOBAL m_hDlgRes;
+ HGLOBAL m_hDlgResSplit;
+
+// Constructor/destructor
+ CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) :
+ CPropertyPageImpl< T, TBase >(title),
+ m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+
+ // initialize ActiveX hosting and modify dialog template
+ ATL::AtlAxWinInit();
+
+ HINSTANCE hInstance = ModuleHelper::GetResourceInstance();
+ LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD);
+ HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG);
+ if(hDlg != NULL)
+ {
+ HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT);
+
+ BYTE* pInitData = NULL;
+ if(hDlgInit != NULL)
+ {
+ m_hInitData = ::LoadResource(hInstance, hDlgInit);
+ pInitData = (BYTE*)::LockResource(m_hInitData);
+ }
+
+ m_hDlgRes = ::LoadResource(hInstance, hDlg);
+ DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes);
+ LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData);
+ if(lpDialogTemplate != pDlg)
+ m_hDlgResSplit = GlobalHandle(lpDialogTemplate);
+
+ // set up property page to use in-memory dialog template
+ if(lpDialogTemplate != NULL)
+ {
+ m_psp.dwFlags |= PSP_DLGINDIRECT;
+ m_psp.pResource = lpDialogTemplate;
+ }
+ else
+ {
+ ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!"));
+ }
+ }
+ else
+ {
+ ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!"));
+ }
+ }
+
+ ~CAxPropertyPageImpl()
+ {
+ if(m_hInitData != NULL)
+ {
+ UnlockResource(m_hInitData);
+ FreeResource(m_hInitData);
+ }
+ if(m_hDlgRes != NULL)
+ {
+ UnlockResource(m_hDlgRes);
+ FreeResource(m_hDlgRes);
+ }
+ if(m_hDlgResSplit != NULL)
+ {
+ ::GlobalFree(m_hDlgResSplit);
+ }
+ }
+
+// Methods
+ // call this one to handle keyboard message for ActiveX controls
+ BOOL PreTranslateMessage(LPMSG pMsg)
+ {
+ if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
+ (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
+ return FALSE;
+ // find a direct child of the dialog from the window that has focus
+ HWND hWndCtl = ::GetFocus();
+ if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd)
+ {
+ do
+ {
+ hWndCtl = ::GetParent(hWndCtl);
+ }
+ while (::GetParent(hWndCtl) != m_hWnd);
+ }
+ // give controls a chance to translate this message
+ return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg);
+ }
+
+// Overridables
+#if (_WIN32_IE >= 0x0500)
+ // new default implementation for ActiveX hosting pages
+#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
+ int OnTranslateAccelerator(LPMSG lpMsg)
+ {
+ T* pT = static_cast<T*>(this);
+ return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
+ }
+#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+ BOOL OnTranslateAccelerator(LPMSG lpMsg)
+ {
+ T* pT = static_cast<T*>(this);
+ return pT->PreTranslateMessage(lpMsg);
+ }
+#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
+#endif // (_WIN32_IE >= 0x0500)
+
+// Support for new stuff in ATL7
+#if (_ATL_VER >= 0x0700)
+ int GetIDD()
+ {
+ return( static_cast<T*>(this)->IDD );
+ }
+
+ virtual DLGPROC GetDialogProc()
+ {
+ return DialogProc;
+ }
+
+ static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd;
+ if (uMsg == WM_INITDIALOG)
+ {
+ HRESULT hr;
+ if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD())))
+ {
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+ }
+ return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam);
+ }
+
+// ActiveX controls creation
+ virtual HRESULT CreateActiveXControls(UINT nID)
+ {
+ // Load dialog template and InitData
+ HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT);
+ BYTE* pInitData = NULL;
+ HGLOBAL hData = NULL;
+ HRESULT hr = S_OK;
+ if (hDlgInit != NULL)
+ {
+ hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit);
+ if (hData != NULL)
+ pInitData = (BYTE*) ::LockResource(hData);
+ }
+
+ HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG);
+ if (hDlg != NULL)
+ {
+ HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg);
+ DLGTEMPLATE* pDlg = NULL;
+ if (hResource != NULL)
+ {
+ pDlg = (DLGTEMPLATE*) ::LockResource(hResource);
+ if (pDlg != NULL)
+ {
+ // Get first control on the template
+ BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg);
+ WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg);
+
+ // Get first control on the dialog
+ DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg);
+ HWND hWndPrev = GetWindow(GW_CHILD);
+
+ // Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order)
+ for (WORD nItem = 0; nItem < nItems; nItem++)
+ {
+ DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id;
+ if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx))
+ {
+ BYTE* pData = NULL;
+ DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData);
+ ATL::CComPtr<IStream> spStream;
+ if (dwLen != 0)
+ {
+ HGLOBAL h = GlobalAlloc(GHND, dwLen);
+ if (h != NULL)
+ {
+ BYTE* pBytes = (BYTE*) GlobalLock(h);
+ BYTE* pSource = pData;
+ SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen);
+ GlobalUnlock(h);
+ CreateStreamOnHGlobal(h, TRUE, &spStream);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ }
+
+ ATL::CComBSTR bstrLicKey;
+ hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str);
+ if (SUCCEEDED(hr))
+ {
+ ATL::CAxWindow2 wnd;
+ // Get control caption.
+ LPWSTR pszClassName =
+ bDialogEx ?
+ (LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) :
+ (LPWSTR)(pItem + 1);
+ // Get control rect.
+ RECT rect;
+ rect.left =
+ bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x :
+ pItem->x;
+ rect.top =
+ bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y :
+ pItem->y;
+ rect.right = rect.left +
+ (bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx :
+ pItem->cx);
+ rect.bottom = rect.top +
+ (bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy :
+ pItem->cy);
+
+ // Convert from dialog units to screen units
+ MapDialogRect(&rect);
+
+ // Create AxWindow with a NULL caption.
+ wnd.Create(m_hWnd,
+ &rect,
+ NULL,
+ (bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style :
+ pItem->style) | WS_TABSTOP,
+ bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle :
+ 0,
+ bDialogEx ?
+ ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id :
+ pItem->id,
+ NULL);
+
+ if (wnd != NULL)
+ {
+#ifndef _WIN32_WCE
+ // Set the Help ID
+ if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0)
+ wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID);
+#endif // !_WIN32_WCE
+ // Try to create the ActiveX control.
+ hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey);
+ if (FAILED(hr))
+ break;
+ // Set the correct tab position.
+ if (nItem == 0)
+ hWndPrev = HWND_TOP;
+ wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ hWndPrev = wnd;
+ }
+ else
+ {
+ hr = ATL::AtlHresultFromLastError();
+ }
+ }
+ }
+ else
+ {
+ if (nItem != 0)
+ hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);
+ }
+ pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx);
+ }
+ }
+ else
+ hr = ATL::AtlHresultFromLastError();
+ }
+ else
+ hr = ATL::AtlHresultFromLastError();
+ }
+ return hr;
+ }
+
+// Event handling support
+ HRESULT AdviseSinkMap(bool bAdvise)
+ {
+ if(!bAdvise && m_hWnd == NULL)
+ {
+ // window is gone, controls are already unadvised
+ ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n"));
+ return S_OK;
+ }
+ HRESULT hRet = E_NOTIMPL;
+ __if_exists(T::_GetSinkMapFinder)
+ {
+ T* pT = static_cast<T*>(this);
+ hRet = AtlAdviseSinkMap(pT, bAdvise);
+ }
+ return hRet;
+ }
+
+// Message map and handlers
+ typedef CPropertyPageImpl< T, TBase> _baseClass;
+ BEGIN_MSG_MAP(CAxPropertyPageImpl)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ CHAIN_MSG_MAP(_baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ // initialize controls in dialog with DLGINIT resource section
+ ExecuteDlgInit(static_cast<T*>(this)->IDD);
+ AdviseSinkMap(true);
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ AdviseSinkMap(false);
+ bHandled = FALSE;
+ return 1;
+ }
+#endif // (_ATL_VER >= 0x0700)
+};
+
+// for non-customized pages
+template <WORD t_wDlgTemplateID>
+class CAxPropertyPage : public CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >
+{
+public:
+ enum { IDD = t_wDlgTemplateID };
+
+ CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl<CAxPropertyPage>(title)
+ { }
+
+#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
+ // not empty so we handle accelerators/create controls
+ BEGIN_MSG_MAP(CAxPropertyPage)
+ CHAIN_MSG_MAP(CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >)
+ END_MSG_MAP()
+#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
+ DECLARE_EMPTY_MSG_MAP()
+#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
+};
+
+#endif // _ATL_NO_HOSTING
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Wizard97 Support
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+// Sample wizard dialog resources:
+//
+// IDD_WIZ97_INTERIOR_BLANK DIALOG 0, 0, 317, 143
+// STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+// CAPTION "Wizard97 Property Page - Interior"
+// FONT 8, "MS Shell Dlg"
+// BEGIN
+// END
+//
+// IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193
+// STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+// CAPTION "Wizard97 Property Page - Welcome/Complete"
+// FONT 8, "MS Shell Dlg", 0, 0, 0x0
+// BEGIN
+// LTEXT "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8,
+// 195,24
+// LTEXT "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)",
+// IDC_STATIC,115,40,195,16
+// LTEXT "h",IDC_WIZ97_BULLET1,118,64,8,8
+// LTEXT "List Item 1 (the h is turned into a bullet)",IDC_STATIC,
+// 127,63,122,8
+// LTEXT "h",IDC_WIZ97_BULLET2,118,79,8,8
+// LTEXT "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC,
+// 127,78,33,8
+// CONTROL "&Do not show this Welcome page again",
+// IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX |
+// WS_TABSTOP,115,169,138,10
+// END
+//
+// GUIDELINES DESIGNINFO
+// BEGIN
+// IDD_WIZ97_INTERIOR_BLANK, DIALOG
+// BEGIN
+// LEFTMARGIN, 7
+// RIGHTMARGIN, 310
+// VERTGUIDE, 21
+// VERTGUIDE, 31
+// VERTGUIDE, 286
+// VERTGUIDE, 296
+// TOPMARGIN, 7
+// BOTTOMMARGIN, 136
+// HORZGUIDE, 8
+// END
+//
+// IDD_WIZ97_EXTERIOR_BLANK, DIALOG
+// BEGIN
+// RIGHTMARGIN, 310
+// VERTGUIDE, 115
+// VERTGUIDE, 118
+// VERTGUIDE, 127
+// TOPMARGIN, 7
+// BOTTOMMARGIN, 186
+// HORZGUIDE, 8
+// HORZGUIDE, 32
+// HORZGUIDE, 40
+// HORZGUIDE, 169
+// END
+// END
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet
+
+class CWizard97SheetWindow : public CPropertySheetWindow
+{
+public:
+// Constructors
+ CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
+ { }
+
+ CWizard97SheetWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Operations
+ HFONT GetExteriorPageTitleFont(void)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L);
+ }
+
+ HFONT GetBulletFont(void)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L);
+ }
+
+// Helpers
+ static UINT GetMessage_GetExteriorPageTitleFont()
+ {
+ static UINT uGetExteriorPageTitleFont = 0;
+ if(uGetExteriorPageTitleFont == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uGetExteriorPageTitleFont == 0)
+ uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12"));
+
+ lock.Unlock();
+ }
+ ATLASSERT(uGetExteriorPageTitleFont != 0);
+ return uGetExteriorPageTitleFont;
+ }
+
+ static UINT GetMessage_GetBulletFont()
+ {
+ static UINT uGetBulletFont = 0;
+ if(uGetBulletFont == 0)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(uGetBulletFont == 0)
+ uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5"));
+
+ lock.Unlock();
+ }
+ ATLASSERT(uGetBulletFont != 0);
+ return uGetBulletFont;
+ }
+
+// Implementation - override to prevent usage
+ HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
+ {
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97SheetImpl - implements a Wizard 97 style wizard sheet
+
+template <class T, class TBase = CWizard97SheetWindow>
+class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase >
+{
+protected:
+// Typedefs
+ typedef CWizard97SheetImpl< T, TBase > thisClass;
+ typedef CPropertySheetImpl< T, TBase > baseClass;
+
+// Member variables
+ CFont m_fontExteriorPageTitle; // Welcome and Completion page title font
+ CFont m_fontBullet; // Bullet font (used on static text 'h' to produce a small bullet)
+ bool m_bReceivedFirstSizeMessage;
+
+public:
+ CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
+ baseClass(title, uStartPage, hWndParent),
+ m_bReceivedFirstSizeMessage(false)
+ {
+ m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP);
+ m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE);
+
+ m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP);
+ m_psh.dwFlags |= PSH_WIZARD97;
+
+ baseClass::SetHeader(headerBitmap.m_lpstr);
+ baseClass::SetWatermark(watermarkBitmap.m_lpstr);
+ }
+
+// Overrides from base class
+ void OnSheetInitialized()
+ {
+ T* pT = static_cast<T*>(this);
+ pT->_InitializeFonts();
+
+ // We'd like to center the wizard here, but its too early.
+ // Instead, we'll do CenterWindow upon our first WM_SIZE message
+ }
+
+// Initialization
+ void _InitializeFonts()
+ {
+ // Setup the Title and Bullet Font
+ // (Property pages can send the "get external page title font" and "get bullet font" messages)
+ // The derived class needs to do the actual SetFont for the dialog items)
+
+ CFontHandle fontThisDialog = this->GetFont();
+ CClientDC dcScreen(NULL);
+
+ LOGFONT titleLogFont = {0};
+ LOGFONT bulletLogFont = {0};
+ fontThisDialog.GetLogFont(&titleLogFont);
+ fontThisDialog.GetLogFont(&bulletLogFont);
+
+ // The Wizard 97 Spec recommends to do the Title Font
+ // as Verdana Bold, 12pt.
+ titleLogFont.lfCharSet = DEFAULT_CHARSET;
+ titleLogFont.lfWeight = FW_BOLD;
+ SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold"));
+ INT titleFontPointSize = 12;
+ titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
+ m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont);
+
+ // The Wizard 97 Spec recommends to do Bullets by having
+ // static text of "h" in the Marlett font.
+ bulletLogFont.lfCharSet = DEFAULT_CHARSET;
+ bulletLogFont.lfWeight = FW_NORMAL;
+ SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett"));
+ INT bulletFontSize = 8;
+ bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
+ m_fontBullet.CreateFontIndirect(&bulletLogFont);
+ }
+
+// Message Handling
+ BEGIN_MSG_MAP(thisClass)
+ MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont)
+ MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ CHAIN_MSG_MAP(baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)(HFONT)m_fontExteriorPageTitle;
+ }
+
+ LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return (LRESULT)(HFONT)m_fontBullet;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(!m_bReceivedFirstSizeMessage)
+ {
+ m_bReceivedFirstSizeMessage = true;
+ this->CenterWindow();
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+};
+
+// for non-customized sheets
+class CWizard97Sheet : public CWizard97SheetImpl<CWizard97Sheet>
+{
+protected:
+// Typedefs
+ typedef CWizard97Sheet thisClass;
+ typedef CWizard97SheetImpl<CWizard97Sheet> baseClass;
+
+public:
+ CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
+ baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent)
+ { }
+
+ BEGIN_MSG_MAP(thisClass)
+ CHAIN_MSG_MAP(baseClass)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97PageWindow - client side for a Wizard 97 style wizard page
+
+#define WIZARD97_EXTERIOR_CXDLG 317
+#define WIZARD97_EXTERIOR_CYDLG 193
+
+#define WIZARD97_INTERIOR_CXDLG 317
+#define WIZARD97_INTERIOR_CYDLG 143
+
+class CWizard97PageWindow : public CPropertyPageWindow
+{
+public:
+// Constructors
+ CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
+ { }
+
+ CWizard97PageWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ CWizard97SheetWindow GetPropertySheet() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return CWizard97SheetWindow(GetParent());
+ }
+
+// Operations
+ HFONT GetExteriorPageTitleFont(void)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return GetPropertySheet().GetExteriorPageTitleFont();
+ }
+
+ HFONT GetBulletFont(void)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return GetPropertySheet().GetBulletFont();
+ }
+
+// Implementation - overrides to prevent usage
+ HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
+ {
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97PageImpl - implements a Wizard 97 style wizard page
+
+template <class T, class TBase = CWizard97PageWindow>
+class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase >
+{
+protected:
+// Typedefs
+ typedef CWizard97PageImpl< T, TBase > thisClass;
+ typedef CPropertyPageImpl< T, TBase > baseClass;
+
+public:
+ CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
+ { }
+
+// Message Handling
+ BEGIN_MSG_MAP(thisClass)
+ CHAIN_MSG_MAP(baseClass)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page
+
+template <class T, class TBase = CWizard97PageWindow>
+class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase >
+{
+protected:
+// Typedefs
+ typedef CWizard97ExteriorPageImpl< T, TBase > thisClass;
+ typedef CPropertyPageImpl< T, TBase > baseClass;
+
+public:
+// Constructors
+ CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
+ {
+ m_psp.dwFlags |= PSP_HASHELP;
+ m_psp.dwFlags |= PSP_HIDEHEADER;
+ }
+
+// Message Handling
+ BEGIN_MSG_MAP(thisClass)
+ CHAIN_MSG_MAP(baseClass)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page
+
+template <class T, class TBase = CWizard97PageWindow>
+class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase >
+{
+protected:
+// Typedefs
+ typedef CWizard97InteriorPageImpl< T, TBase > thisClass;
+ typedef CPropertyPageImpl< T, TBase > baseClass;
+
+public:
+// Constructors
+ CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
+ {
+ m_psp.dwFlags |= PSP_HASHELP;
+ m_psp.dwFlags &= ~PSP_HIDEHEADER;
+ m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+
+ // Be sure to have the derived class define this in the constructor.
+ // We'll default it to something obvious in case its forgotten.
+ baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class"));
+ baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class."));
+ }
+
+// Message Handling
+ BEGIN_MSG_MAP(thisClass)
+ CHAIN_MSG_MAP(baseClass)
+ END_MSG_MAP()
+};
+
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Aero Wizard support
+
+#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardFrameWindow - client side for an Aero Wizard frame window
+
+class CAeroWizardFrameWindow : public CPropertySheetWindow
+{
+public:
+// Constructors
+ CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
+ { }
+
+ CAeroWizardFrameWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Operations - new, Aero Wizard only
+ void SetNextText(LPCWSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText);
+ }
+
+ void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
+ }
+
+ void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
+ }
+
+ void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardFrameImpl - implements an Aero Wizard frame
+
+template <class T, class TBase = CAeroWizardFrameWindow>
+class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl<T, TBase >
+{
+public:
+// Constructor
+ CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) :
+ CPropertySheetImpl<T, TBase >(title, uStartPage, hWndParent)
+ {
+ m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD;
+ }
+
+// Operations
+ void EnableResizing()
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ m_psh.dwFlags |= PSH_RESIZABLE;
+ }
+
+ void UseHeaderBitmap()
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ m_psh.dwFlags |= PSH_HEADERBITMAP;
+ }
+
+ void SetNoMargin()
+ {
+ ATLASSERT(m_hWnd == NULL); // can't do this after it's created
+ m_psh.dwFlags |= PSH_NOMARGIN;
+ }
+
+// Override to prevent use
+ HWND Create(HWND /*hWndParent*/ = NULL)
+ {
+ ATLASSERT(FALSE); // not supported for Aero Wizard
+ return NULL;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardFrame - for non-customized frames
+
+class CAeroWizardFrame : public CAeroWizardFrameImpl<CAeroWizardFrame>
+{
+public:
+ CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
+ : CAeroWizardFrameImpl<CAeroWizardFrame>(title, uStartPage, hWndParent)
+ { }
+
+ BEGIN_MSG_MAP(CAeroWizardFrame)
+ MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl<CAeroWizardFrame>::OnCommand)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardPageWindow - client side for an Aero Wizard page
+
+class CAeroWizardPageWindow : public CPropertyPageWindow
+{
+public:
+// Constructors
+ CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
+ { }
+
+ CAeroWizardPageWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Attributes
+ CAeroWizardFrameWindow GetAeroWizardFrame() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ // This is not really top-level frame window, but it processes all frame messages
+ return CAeroWizardFrameWindow(GetParent());
+ }
+
+// Operations - new, Aero Wizard only
+ void SetNextText(LPCWSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetAeroWizardFrame().SetNextText(lpszText);
+ }
+
+ void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates);
+ }
+
+ void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates);
+ }
+
+ void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetParent() != NULL);
+ GetAeroWizardFrame().SetButtonText(dwButton, lpszText);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardPageImpl - implements an Aero Wizard page
+
+template <class T, class TBase = CAeroWizardPageWindow>
+class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl<T, TBase >
+{
+public:
+ CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<T, TBase >(title)
+ { }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardPage - for non-customized pages
+
+template <WORD t_wDlgTemplateID>
+class CAeroWizardPage : public CAeroWizardPageImpl<CAeroWizardPage<t_wDlgTemplateID> >
+{
+public:
+ enum { IDD = t_wDlgTemplateID };
+
+ CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl<CAeroWizardPage>(title)
+ { }
+
+ DECLARE_EMPTY_MSG_MAP()
+};
+
+
+#ifndef _ATL_NO_HOSTING
+
+// Note: You must #include <atlhost.h> to use these classes
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls
+
+template <class T, class TBase = CAeroWizardPageWindow>
+class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase >
+{
+public:
+ CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title)
+ { }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroWizardAxPage - for non-customized pages
+
+template <WORD t_wDlgTemplateID>
+class CAeroWizardAxPage : public CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >
+{
+public:
+ enum { IDD = t_wDlgTemplateID };
+
+ CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl<CAeroWizardAxPage>(title)
+ { }
+
+#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
+ // not empty so we handle accelerators/create controls
+ BEGIN_MSG_MAP(CAeroWizardAxPage)
+ CHAIN_MSG_MAP(CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >)
+ END_MSG_MAP()
+#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
+ DECLARE_EMPTY_MSG_MAP()
+#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
+};
+
+#endif // _ATL_NO_HOSTING
+
+#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TaskDialog support
+
+#if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
+
+///////////////////////////////////////////////////////////////////////////////
+// AtlTaskDialog - support for TaskDialog() function
+
+inline int AtlTaskDialog(HWND hWndParent,
+ ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText,
+ TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL)
+{
+ int nRet = -1;
+
+#ifdef _WTL_TASKDIALOG_DIRECT
+ USES_CONVERSION;
+ HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(),
+ IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr),
+ IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr),
+ IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr),
+ dwCommonButtons,
+ IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),
+ &nRet);
+ ATLVERIFY(SUCCEEDED(hRet));
+#else
+ // This allows apps to run on older versions of Windows
+ typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton);
+
+ HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
+ if(m_hCommCtrlDLL != NULL)
+ {
+ PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog");
+ if(pfnTaskDialog != NULL)
+ {
+ USES_CONVERSION;
+ HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(),
+ IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr),
+ IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr),
+ IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr),
+ dwCommonButtons,
+ IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),
+ &nRet);
+ ATLVERIFY(SUCCEEDED(hRet));
+ }
+
+ ::FreeLibrary(m_hCommCtrlDLL);
+ }
+#endif
+
+ return nRet;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTaskDialogConfig - TASKDIALOGCONFIG wrapper
+
+class CTaskDialogConfig : public TASKDIALOGCONFIG
+{
+public:
+// Constructor
+ CTaskDialogConfig()
+ {
+ Init();
+ }
+
+ void Init()
+ {
+ memset(this, 0, sizeof(TASKDIALOGCONFIG)); // initialize structure to 0/NULL
+ this->cbSize = sizeof(TASKDIALOGCONFIG);
+ this->hInstance = ModuleHelper::GetResourceInstance();
+ }
+
+// Operations - setting values
+ // common buttons
+ void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
+ {
+ this->dwCommonButtons = dwCommonButtons;
+ }
+
+ // window title text
+ void SetWindowTitle(UINT nID)
+ {
+ this->pszWindowTitle = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetWindowTitle(LPCWSTR lpstrWindowTitle)
+ {
+ this->pszWindowTitle = lpstrWindowTitle;
+ }
+
+ // main icon
+ void SetMainIcon(HICON hIcon)
+ {
+ this->dwFlags |= TDF_USE_HICON_MAIN;
+ this->hMainIcon = hIcon;
+ }
+
+ void SetMainIcon(UINT nID)
+ {
+ this->dwFlags &= ~TDF_USE_HICON_MAIN;
+ this->pszMainIcon = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetMainIcon(LPCWSTR lpstrMainIcon)
+ {
+ this->dwFlags &= ~TDF_USE_HICON_MAIN;
+ this->pszMainIcon = lpstrMainIcon;
+ }
+
+ // main instruction text
+ void SetMainInstructionText(UINT nID)
+ {
+ this->pszMainInstruction = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
+ {
+ this->pszMainInstruction = lpstrMainInstruction;
+ }
+
+ // content text
+ void SetContentText(UINT nID)
+ {
+ this->pszContent = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetContentText(LPCWSTR lpstrContent)
+ {
+ this->pszContent = lpstrContent;
+ }
+
+ // buttons
+ void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)
+ {
+ this->pButtons = pButtons;
+ this->cButtons = cButtons;
+ if(nDefaultButton != 0)
+ this->nDefaultButton = nDefaultButton;
+ }
+
+ void SetDefaultButton(int nDefaultButton)
+ {
+ this->nDefaultButton = nDefaultButton;
+ }
+
+ // radio buttons
+ void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)
+ {
+ this->pRadioButtons = pRadioButtons;
+ this->cRadioButtons = cRadioButtons;
+ if(nDefaultRadioButton != 0)
+ this->nDefaultRadioButton = nDefaultRadioButton;
+ }
+
+ void SetDefaultRadioButton(int nDefaultRadioButton)
+ {
+ this->nDefaultRadioButton = nDefaultRadioButton;
+ }
+
+ // verification text
+ void SetVerificationText(UINT nID)
+ {
+ this->pszVerificationText = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetVerificationText(LPCWSTR lpstrVerificationText)
+ {
+ this->pszVerificationText = lpstrVerificationText;
+ }
+
+ // expanded information text
+ void SetExpandedInformationText(UINT nID)
+ {
+ this->pszExpandedInformation = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
+ {
+ this->pszExpandedInformation = lpstrExpandedInformation;
+ }
+
+ // expanded control text
+ void SetExpandedControlText(UINT nID)
+ {
+ this->pszExpandedControlText = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
+ {
+ this->pszExpandedControlText = lpstrExpandedControlText;
+ }
+
+ // collapsed control text
+ void SetCollapsedControlText(UINT nID)
+ {
+ this->pszCollapsedControlText = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
+ {
+ this->pszCollapsedControlText = lpstrCollapsedControlText;
+ }
+
+ // footer icon
+ void SetFooterIcon(HICON hIcon)
+ {
+ this->dwFlags |= TDF_USE_HICON_FOOTER;
+ this->hFooterIcon = hIcon;
+ }
+
+ void SetFooterIcon(UINT nID)
+ {
+ this->dwFlags &= ~TDF_USE_HICON_FOOTER;
+ this->pszFooterIcon = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetFooterIcon(LPCWSTR lpstrFooterIcon)
+ {
+ this->dwFlags &= ~TDF_USE_HICON_FOOTER;
+ this->pszFooterIcon = lpstrFooterIcon;
+ }
+
+ // footer text
+ void SetFooterText(UINT nID)
+ {
+ this->pszFooter = MAKEINTRESOURCEW(nID);
+ }
+
+ void SetFooterText(LPCWSTR lpstrFooterText)
+ {
+ this->pszFooter = lpstrFooterText;
+ }
+
+ // width (in DLUs)
+ void SetWidth(UINT cxWidth)
+ {
+ this->cxWidth = cxWidth;
+ }
+
+ // modify flags
+ void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
+ {
+ this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTaskDialogImpl - implements a Task Dialog
+
+template <class T>
+class ATL_NO_VTABLE CTaskDialogImpl
+{
+public:
+ CTaskDialogConfig m_tdc;
+ HWND m_hWnd; // used only in callback functions
+
+// Constructor
+ CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL)
+ {
+ m_tdc.hwndParent = hWndParent;
+ m_tdc.pfCallback = T::TaskDialogCallback;
+ m_tdc.lpCallbackData = (LONG_PTR)static_cast<T*>(this);
+ }
+
+// Operations
+ HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL)
+ {
+ if(m_tdc.hwndParent == NULL)
+ m_tdc.hwndParent = hWndParent;
+
+#ifdef _WTL_TASKDIALOG_DIRECT
+ return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
+#else
+
+ // This allows apps to run on older versions of Windows
+ typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked);
+
+ HRESULT hRet = E_UNEXPECTED;
+ HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
+ if(m_hCommCtrlDLL != NULL)
+ {
+ PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect");
+ if(pfnTaskDialogIndirect != NULL)
+ hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
+
+ ::FreeLibrary(m_hCommCtrlDLL);
+ }
+
+ return hRet;
+#endif
+ }
+
+// Operations - setting values of TASKDIALOGCONFIG
+ // common buttons
+ void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
+ { m_tdc.SetCommonButtons(dwCommonButtons); }
+ // window title text
+ void SetWindowTitle(UINT nID)
+ { m_tdc.SetWindowTitle(nID); }
+ void SetWindowTitle(LPCWSTR lpstrWindowTitle)
+ { m_tdc.SetWindowTitle(lpstrWindowTitle); }
+ // main icon
+ void SetMainIcon(HICON hIcon)
+ { m_tdc.SetMainIcon(hIcon); }
+ void SetMainIcon(UINT nID)
+ { m_tdc.SetMainIcon(nID); }
+ void SetMainIcon(LPCWSTR lpstrMainIcon)
+ { m_tdc.SetMainIcon(lpstrMainIcon); }
+ // main instruction text
+ void SetMainInstructionText(UINT nID)
+ { m_tdc.SetMainInstructionText(nID); }
+ void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
+ { m_tdc.SetMainInstructionText(lpstrMainInstruction); }
+ // content text
+ void SetContentText(UINT nID)
+ { m_tdc.SetContentText(nID); }
+ void SetContentText(LPCWSTR lpstrContent)
+ { m_tdc.SetContentText(lpstrContent); }
+ // buttons
+ void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)
+ { m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); }
+ void SetDefaultButton(int nDefaultButton)
+ { m_tdc.SetDefaultButton(nDefaultButton); }
+ // radio buttons
+ void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)
+ { m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); }
+ void SetDefaultRadioButton(int nDefaultRadioButton)
+ { m_tdc.SetDefaultRadioButton(nDefaultRadioButton); }
+ // verification text
+ void SetVerificationText(UINT nID)
+ { m_tdc.SetVerificationText(nID); }
+ void SetVerificationText(LPCWSTR lpstrVerificationText)
+ { m_tdc.SetVerificationText(lpstrVerificationText); }
+ // expanded information text
+ void SetExpandedInformationText(UINT nID)
+ { m_tdc.SetExpandedInformationText(nID); }
+ void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
+ { m_tdc.SetExpandedInformationText(lpstrExpandedInformation); }
+ // expanded control text
+ void SetExpandedControlText(UINT nID)
+ { m_tdc.SetExpandedControlText(nID); }
+ void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
+ { m_tdc.SetExpandedControlText(lpstrExpandedControlText); }
+ // collapsed control text
+ void SetCollapsedControlText(UINT nID)
+ { m_tdc.SetCollapsedControlText(nID); }
+ void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
+ { m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); }
+ // footer icon
+ void SetFooterIcon(HICON hIcon)
+ { m_tdc.SetFooterIcon(hIcon); }
+ void SetFooterIcon(UINT nID)
+ { m_tdc.SetFooterIcon(nID); }
+ void SetFooterIcon(LPCWSTR lpstrFooterIcon)
+ { m_tdc.SetFooterIcon(lpstrFooterIcon); }
+ // footer text
+ void SetFooterText(UINT nID)
+ { m_tdc.SetFooterText(nID); }
+ void SetFooterText(LPCWSTR lpstrFooterText)
+ { m_tdc.SetFooterText(lpstrFooterText); }
+ // width (in DLUs)
+ void SetWidth(UINT cxWidth)
+ { m_tdc.SetWidth(cxWidth); }
+ // modify flags
+ void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
+ { m_tdc.ModifyFlags(dwRemove, dwAdd); }
+
+// Implementation
+ static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData)
+ {
+ T* pT = (T*)lpRefData;
+ ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd);
+
+ BOOL bRet = FALSE;
+ switch(uMsg)
+ {
+ case TDN_DIALOG_CONSTRUCTED:
+ pT->m_hWnd = hWnd;
+ pT->OnDialogConstructed();
+ break;
+ case TDN_CREATED:
+ pT->OnCreated();
+ break;
+ case TDN_BUTTON_CLICKED:
+ bRet = pT->OnButtonClicked((int)wParam);
+ break;
+ case TDN_RADIO_BUTTON_CLICKED:
+ pT->OnRadioButtonClicked((int)wParam);
+ break;
+ case TDN_HYPERLINK_CLICKED:
+ pT->OnHyperlinkClicked((LPCWSTR)lParam);
+ break;
+ case TDN_EXPANDO_BUTTON_CLICKED:
+ pT->OnExpandoButtonClicked((wParam != 0));
+ break;
+ case TDN_VERIFICATION_CLICKED:
+ pT->OnVerificationClicked((wParam != 0));
+ break;
+ case TDN_HELP:
+ pT->OnHelp();
+ break;
+ case TDN_TIMER:
+ bRet = pT->OnTimer((DWORD)wParam);
+ break;
+ case TDN_NAVIGATED:
+ pT->OnNavigated();
+ break;
+ case TDN_DESTROYED:
+ pT->OnDestroyed();
+ pT->m_hWnd = NULL;
+ break;
+ default:
+ ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n"));
+ break;
+ }
+
+ return (HRESULT)bRet;
+ }
+
+// Overrideables - notification handlers
+ void OnDialogConstructed()
+ {
+ }
+
+ void OnCreated()
+ {
+ }
+
+ BOOL OnButtonClicked(int /*nButton*/)
+ {
+ return FALSE; // don't prevent dialog to close
+ }
+
+ void OnRadioButtonClicked(int /*nRadioButton*/)
+ {
+ }
+
+ void OnHyperlinkClicked(LPCWSTR /*pszHREF*/)
+ {
+ }
+
+ void OnExpandoButtonClicked(bool /*bExpanded*/)
+ {
+ }
+
+ void OnVerificationClicked(bool /*bChecked*/)
+ {
+ }
+
+ void OnHelp()
+ {
+ }
+
+ BOOL OnTimer(DWORD /*dwTickCount*/)
+ {
+ return FALSE; // don't reset counter
+ }
+
+ void OnNavigated()
+ {
+ }
+
+ void OnDestroyed()
+ {
+ }
+
+// Commands - valid to call only from handlers
+ void NavigatePage(TASKDIALOGCONFIG& tdc)
+ {
+ ATLASSERT(m_hWnd != NULL);
+
+ tdc.cbSize = sizeof(TASKDIALOGCONFIG);
+ if(tdc.hwndParent == NULL)
+ tdc.hwndParent = m_tdc.hwndParent;
+ tdc.pfCallback = m_tdc.pfCallback;
+ tdc.lpCallbackData = m_tdc.lpCallbackData;
+ (TASKDIALOGCONFIG)m_tdc = tdc;
+
+ ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc);
+ }
+
+ // modify TASKDIALOGCONFIG values, then call this to update task dialog
+ void NavigatePage()
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc);
+ }
+
+ void ClickButton(int nButton)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L);
+ }
+
+ void SetMarqueeProgressBar(BOOL bMarquee)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L);
+ }
+
+ BOOL SetProgressBarState(int nNewState)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L);
+ }
+
+ DWORD SetProgressBarRange(int nMinRange, int nMaxRange)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange));
+ }
+
+ int SetProgressBarPos(int nNewPos)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L);
+ }
+
+ BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed);
+ }
+
+ void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText);
+ }
+
+ void ClickRadioButton(int nRadioButton)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L);
+ }
+
+ void EnableButton(int nButton, BOOL bEnable)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable);
+ }
+
+ void EnableRadioButton(int nButton, BOOL bEnable)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable);
+ }
+
+ void ClickVerification(BOOL bCheck, BOOL bFocus)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus);
+ }
+
+ void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText);
+ }
+
+ void SetButtonElevationRequiredState(int nButton, BOOL bElevation)
+ {
+ ATLASSERT(m_hWnd != NULL);
+ ::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation);
+ }
+
+ void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon)
+ {
+ ATLASSERT(m_hWnd != NULL);
+#ifdef _DEBUG
+ if(element == TDIE_ICON_MAIN)
+ ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0);
+ else if(element == TDIE_ICON_FOOTER)
+ ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0);
+#endif // _DEBUG
+ ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon);
+ }
+
+ void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon)
+ {
+ ATLASSERT(m_hWnd != NULL);
+#ifdef _DEBUG
+ if(element == TDIE_ICON_MAIN)
+ ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0);
+ else if(element == TDIE_ICON_FOOTER)
+ ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0);
+#endif // _DEBUG
+ ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTaskDialog - for non-customized task dialogs
+
+class CTaskDialog : public CTaskDialogImpl<CTaskDialog>
+{
+public:
+ CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl<CTaskDialog>(hWndParent)
+ {
+ m_tdc.pfCallback = NULL;
+ }
+};
+
+#endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
+
+}; // namespace WTL
+
+#endif // __ATLDLGS_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLDWM_H__
+#define __ATLDWM_H__
+
+#pragma once
+
+#ifdef _WIN32_WCE
+ #error atldwm.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLAPP_H__
+ #error atldwm.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atldwm.h requires atlwin.h to be included first
+#endif
+
+#if (_WIN32_WINNT < 0x0600)
+ #error atldwm.h requires _WIN32_WINNT >= 0x0600
+#endif // (_WIN32_WINNT < 0x0600)
+
+#ifndef _DWMAPI_H_
+#include <dwmapi.h>
+#endif // _DWMAPI_H_
+#pragma comment(lib, "dwmapi.lib")
+
+// Note: To create an application that also runs on older versions of Windows,
+// use delay load of dwmapi.dll and ensure that no calls to the DWM API are
+// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib,
+// and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the
+// project properties.
+#if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD)
+ #pragma comment(lib, "delayimp.lib")
+ #pragma comment(linker, "/delayload:dwmapi.dll")
+#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD)
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CDwm
+// CDwmImpl<T, TBase>
+// CDwmWindowT<TBase> - CDwmWindow
+// CDwmThumbnailT<t_bManaged, TBase>
+// CDwmThumbnail
+// CDwmThumbnailHandle
+// CAeroControlImpl
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CDwm - wrapper for DWM handle
+
+class CDwm
+{
+public:
+// Data members
+ static int m_nIsDwmSupported;
+
+// Constructor
+ CDwm()
+ {
+ IsDwmSupported();
+ }
+
+// Dwm support helper
+ static bool IsDwmSupported()
+ {
+ if(m_nIsDwmSupported == -1)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\n"));
+ ATLASSERT(FALSE);
+ return false;
+ }
+
+ if(m_nIsDwmSupported == -1)
+ {
+ HMODULE hDwmDLL = ::LoadLibrary(_T("dwmapi.dll"));
+ m_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0;
+ if(hDwmDLL != NULL)
+ ::FreeLibrary(hDwmDLL);
+ }
+
+ lock.Unlock();
+ }
+
+ ATLASSERT(m_nIsDwmSupported != -1);
+ return (m_nIsDwmSupported == 1);
+ }
+
+// Operations
+ BOOL DwmIsCompositionEnabled() const
+ {
+ if(!IsDwmSupported()) return FALSE;
+ BOOL bRes = FALSE;
+ return SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes;
+ }
+
+ BOOL DwmEnableComposition(UINT fEnable)
+ {
+ if(!IsDwmSupported()) return FALSE;
+ return SUCCEEDED(::DwmEnableComposition(fEnable));
+ }
+
+ BOOL DwmEnableMMCSS(BOOL fEnableMMCSS)
+ {
+ if(!IsDwmSupported()) return FALSE;
+ return SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS));
+ }
+
+ HRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ return ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend);
+ }
+
+ HRESULT DwmFlush()
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ return ::DwmFlush();
+ }
+};
+
+__declspec(selectany) int CDwm::m_nIsDwmSupported = -1;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDwmImpl - DWM window support
+
+template <class T, class TBase = CDwm>
+class CDwmImpl : public TBase
+{
+public:
+ HRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB);
+ }
+
+ HRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins);
+ }
+
+ HRESULT DwmExtendFrameIntoEntireClientArea()
+ {
+ MARGINS margins = { -1 };
+ return DwmExtendFrameIntoClientArea(&margins);
+ }
+
+ HRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo);
+ }
+
+ HRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute);
+ }
+
+ HRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative);
+ }
+
+ HRESULT DwmSetDxFrameDuration(INT cRefreshes)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes);
+ }
+
+ HRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams);
+ }
+
+ HRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute);
+ }
+
+ HRESULT DwmAttachMilContent()
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmAttachMilContent(pT->m_hWnd);
+ }
+
+ HRESULT DwmDetachMilContent()
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DwmDetachMilContent(pT->m_hWnd);
+ }
+};
+
+template <class TBase>
+class CDwmWindowT : public TBase, public CDwmImpl<CDwmWindowT< TBase > >
+{
+public:
+ CDwmWindowT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CDwmWindowT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+};
+
+typedef CDwmWindowT<ATL::CWindow> CDwmWindow;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDwmThumbnail - provides DWM thumbnail support
+
+template <bool t_bManaged, class TBase = CDwm>
+class CDwmThumbnailT : public TBase
+{
+public:
+// Data members
+ HTHUMBNAIL m_hThumbnail;
+
+// Constructor
+ CDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail)
+ {
+ }
+
+ ~CDwmThumbnailT()
+ {
+ if(t_bManaged && m_hThumbnail != NULL)
+ Unregister();
+ }
+
+// Operations
+ CDwmThumbnailT<t_bManaged, TBase>& operator =(HTHUMBNAIL hThumbnail)
+ {
+ Attach(hThumbnail);
+ return *this;
+ }
+
+ void Attach(HTHUMBNAIL hThumbnailNew)
+ {
+ if(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew)
+ Unregister();
+ m_hThumbnail = hThumbnailNew;
+ }
+
+ HTHUMBNAIL Detach()
+ {
+ HTHUMBNAIL hThumbnail = m_hThumbnail;
+ m_hThumbnail = NULL;
+ return hThumbnail;
+ }
+
+ HRESULT Register(HWND hwndDestination, HWND hwndSource)
+ {
+ ATLASSERT(::IsWindow(hwndDestination));
+ ATLASSERT(::IsWindow(hwndSource));
+ ATLASSERT(m_hThumbnail==NULL);
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ return ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail);
+ }
+
+ HRESULT Unregister()
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ if(m_hThumbnail == NULL) return S_FALSE;
+ HRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail);
+ if(SUCCEEDED(Hr)) m_hThumbnail = NULL;
+ return Hr;
+ }
+
+ operator HTHUMBNAIL() const { return m_hThumbnail; }
+
+ bool IsNull() const { return (m_hThumbnail == NULL); }
+
+ HRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ ATLASSERT(m_hThumbnail != NULL);
+ return ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties);
+ }
+
+// Attributes
+ HRESULT QuerySourceSize(PSIZE pSize)
+ {
+ if(!IsDwmSupported()) return E_NOTIMPL;
+ ATLASSERT(m_hThumbnail != NULL);
+ return ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize);
+ }
+};
+
+typedef CDwmThumbnailT<true, CDwm> CDwmThumbnail;
+typedef CDwmThumbnailT<false, CDwm> CDwmThumbnailHandle;
+
+
+#ifdef __ATLTHEME_H__
+
+///////////////////////////////////////////////////////////////////////////////
+// CAeroControlImpl - Base class for controls on Glass
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class CAeroControlImpl :
+ public CThemeImpl<T>,
+ public CBufferedPaintImpl<T>,
+ public ATL::CWindowImpl<T, TBase, TWinTraits>
+{
+public:
+ typedef CThemeImpl<T> _themeClass;
+ typedef CBufferedPaintImpl<T> _baseClass;
+ typedef ATL::CWindowImpl<T, TBase, TWinTraits> _windowClass;
+
+ CAeroControlImpl()
+ {
+ m_PaintParams.dwFlags = BPPF_ERASE;
+ }
+
+ static LPCWSTR GetThemeName()
+ {
+#ifdef _UNICODE
+ return TBase::GetWndClassName();
+#else
+ ATLASSERT(!_T("Return UNICODE string of window classname / theme class"));
+ return NULL;
+#endif // _UNICODE
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CAeroControlImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
+ CHAIN_MSG_MAP(_themeClass)
+ CHAIN_MSG_MAP(_baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Init();
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(IsThemingSupported()) Invalidate(FALSE);
+ bHandled = FALSE;
+ return 0;
+ }
+
+// Operations
+ BOOL SubclassWindow(HWND hWnd)
+ {
+ ATLASSERT(m_hWnd == NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ BOOL bRet = _windowClass::SubclassWindow(hWnd);
+ if(bRet) {
+ T* pT = static_cast<T*>(this);
+ pT->Init();
+ }
+ return bRet;
+ }
+
+// Implementation
+ LRESULT DefWindowProc()
+ {
+ const _ATL_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)
+ {
+ T* pT = static_cast<T*>(this);
+ LRESULT lRes = 0;
+ if( ::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) ) return lRes;
+ return _windowClass::DefWindowProc(uMsg, wParam, lParam);
+ }
+
+ void DoBufferedPaint(HDC hDC, RECT& rcPaint)
+ {
+ T* pT = static_cast<T*>(this);
+ HDC hDCPaint = NULL;
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ m_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint);
+ ATLASSERT(hDCPaint != NULL);
+ pT->DoAeroPaint(hDCPaint, rcClient, rcPaint);
+ m_BufferedPaint.End();
+ }
+
+ void DoPaint(HDC /*hdc*/, RECT& /*rcClient*/)
+ {
+ DefWindowProc();
+ }
+
+// Overridables
+ void Init()
+ {
+ T* pT = static_cast<T*>(this);
+ SetThemeClassList(pT->GetThemeName());
+ if(m_lpstrThemeClassList != NULL)
+ OpenThemeData();
+ }
+
+ void DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint)
+ {
+ DefWindowProc(WM_PAINT, (WPARAM) hDC, 0L);
+ m_BufferedPaint.MakeOpaque(&rcPaint);
+ }
+};
+
+#endif // __ATLTHEME_H__
+
+
+}; // namespace WTL
+
+
+#endif // __ATLDWM_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLFIND_H__
+#define __ATLFIND_H__
+
+#pragma once
+
+#ifdef _WIN32_WCE
+ #error atlfind.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLCTRLS_H__
+ #error atlfind.h requires atlctrls.h to be included first
+#endif
+
+#ifndef __ATLDLGS_H__
+ #error atlfind.h requires atldlgs.h to be included first
+#endif
+
+#if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__))
+ #error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING)
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CEditFindReplaceImplBase<T, TFindReplaceDialog>
+// CEditFindReplaceImpl<T, TFindReplaceDialog>
+// CRichEditFindReplaceImpl<T, TFindReplaceDialog>
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CEditFindReplaceImplBase - Base class for mixin classes that
+// help implement Find/Replace for CEdit or CRichEditCtrl based window classes.
+
+template <class T, class TFindReplaceDialog = CFindReplaceDialog>
+class CEditFindReplaceImplBase
+{
+protected:
+// Typedefs
+ typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> thisClass;
+
+// Data members
+ TFindReplaceDialog* m_pFindReplaceDialog;
+ _CSTRING_NS::CString m_sFindNext, m_sReplaceWith;
+ BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown;
+ LONG m_nInitialSearchPos;
+ HCURSOR m_hOldCursor;
+
+// Enumerations
+ enum TranslationTextItem
+ {
+ eText_OnReplaceAllMessage = 0,
+ eText_OnReplaceAllTitle = 1,
+ eText_OnTextNotFoundMessage = 2,
+ eText_OnTextNotFoundTitle = 3
+ };
+
+public:
+// Constructors
+ CEditFindReplaceImplBase() :
+ m_pFindReplaceDialog(NULL),
+ m_bFindOnly(TRUE),
+ m_bFirstSearch(TRUE),
+ m_bMatchCase(FALSE),
+ m_bWholeWord(FALSE),
+ m_bFindDown(TRUE),
+ m_nInitialSearchPos(0),
+ m_hOldCursor(NULL)
+ {
+ }
+
+// Message Handlers
+ BEGIN_MSG_MAP(thisClass)
+ ALT_MSG_MAP(1)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd)
+ COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind)
+ COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat)
+ COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace)
+ END_MSG_MAP()
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_pFindReplaceDialog != NULL)
+ {
+ m_pFindReplaceDialog->SendMessage(WM_CLOSE);
+ ATLASSERT(m_pFindReplaceDialog == NULL);
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+
+ TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam);
+ if(pDialog == NULL)
+ {
+ ATLASSERT(FALSE);
+ ::MessageBeep(MB_ICONERROR);
+ return 1;
+ }
+ ATLASSERT(pDialog == m_pFindReplaceDialog);
+
+ LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam;
+ if((m_pFindReplaceDialog != NULL) && (findReplace != NULL))
+ {
+ if(pDialog->FindNext())
+ {
+ pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(),
+ pDialog->MatchCase(), pDialog->MatchWholeWord());
+ }
+ else if(pDialog->ReplaceCurrent())
+ {
+ pT->OnReplaceSel(pDialog->GetFindString(),
+ pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(),
+ pDialog->GetReplaceString());
+ }
+ else if(pDialog->ReplaceAll())
+ {
+ pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
+ pDialog->MatchCase(), pDialog->MatchWholeWord());
+ }
+ else if(pDialog->IsTerminating())
+ {
+ // Dialog is going away (but hasn't gone away yet)
+ // OnFinalMessage will "delete this"
+ pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog);
+ m_pFindReplaceDialog = NULL;
+ }
+ }
+
+ return 0;
+ }
+
+ LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->FindReplace(TRUE);
+
+ return 0;
+ }
+
+ LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+
+ // If the user is holding down SHIFT when hitting F3, we'll
+ // search in reverse. Otherwise, we'll search forward.
+ // (be sure to have an accelerator mapped to ID_EDIT_REPEAT
+ // for both F3 and Shift+F3)
+ m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);
+
+ if(m_sFindNext.IsEmpty())
+ {
+ pT->FindReplace(TRUE);
+ }
+ else
+ {
+ if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
+ pT->TextNotFound(m_sFindNext);
+ }
+
+ return 0;
+ }
+
+ LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+
+ DWORD style = pT->GetStyle();
+ if((style & ES_READONLY) != ES_READONLY)
+ {
+ pT->FindReplace(FALSE);
+ }
+ else
+ {
+ // Don't allow replace when the edit control is read only
+ bHandled = FALSE;
+ }
+
+ return 0;
+ }
+
+// Operations (overrideable)
+ TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace
+ LPCTSTR lpszFindWhat,
+ LPCTSTR lpszReplaceWith = NULL,
+ DWORD dwFlags = FR_DOWN,
+ HWND hWndParent = NULL)
+ {
+ // You can override all of this in a derived class
+
+ TFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog();
+ if(findReplaceDialog == NULL)
+ {
+ ::MessageBeep(MB_ICONHAND);
+ }
+ else
+ {
+ HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly,
+ lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent);
+ if(hWndFindReplace == NULL)
+ {
+ delete findReplaceDialog;
+ findReplaceDialog = NULL;
+ }
+ else
+ {
+ findReplaceDialog->SetActiveWindow();
+ findReplaceDialog->ShowWindow(SW_SHOW);
+ }
+ }
+
+ return findReplaceDialog;
+ }
+
+ void AdjustDialogPosition(HWND hWndDialog)
+ {
+ ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog));
+
+ T* pT = static_cast<T*>(this);
+ LONG nStartChar = 0, nEndChar = 0;
+ // Send EM_GETSEL so we can use both Edit and RichEdit
+ // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)
+ ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
+ POINT point = pT->PosFromChar(nStartChar);
+ ::ClientToScreen(pT->GetParent(), &point);
+ CRect rect;
+ ::GetWindowRect(hWndDialog, &rect);
+ if(rect.PtInRect(point))
+ {
+ if(point.y > rect.Height())
+ {
+ rect.OffsetRect(0, point.y - rect.bottom - 20);
+ }
+ else
+ {
+ int nVertExt = GetSystemMetrics(SM_CYSCREEN);
+ if(point.y + rect.Height() < nVertExt)
+ rect.OffsetRect(0, 40 + point.y - rect.top);
+ }
+
+ ::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE);
+ }
+ }
+
+ DWORD GetFindReplaceDialogFlags(void) const
+ {
+ DWORD dwFlags = 0;
+
+ if(m_bFindDown)
+ dwFlags |= FR_DOWN;
+ if(m_bMatchCase)
+ dwFlags |= FR_MATCHCASE;
+ if(m_bWholeWord)
+ dwFlags |= FR_WHOLEWORD;
+
+ return dwFlags;
+ }
+
+ void FindReplace(BOOL bFindOnly)
+ {
+ T* pT = static_cast<T*>(this);
+ m_bFirstSearch = TRUE;
+ if(m_pFindReplaceDialog != NULL)
+ {
+ if(m_bFindOnly == bFindOnly)
+ {
+ m_pFindReplaceDialog->SetActiveWindow();
+ m_pFindReplaceDialog->ShowWindow(SW_SHOW);
+ return;
+ }
+ else
+ {
+ m_pFindReplaceDialog->SendMessage(WM_CLOSE);
+ ATLASSERT(m_pFindReplaceDialog == NULL);
+ }
+ }
+
+ ATLASSERT(m_pFindReplaceDialog == NULL);
+
+ _CSTRING_NS::CString findNext;
+ pT->GetSelText(findNext);
+ // if selection is empty or spans multiple lines use old find text
+ if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1))
+ findNext = m_sFindNext;
+ _CSTRING_NS::CString replaceWith = m_sReplaceWith;
+ DWORD dwFlags = pT->GetFindReplaceDialogFlags();
+
+ m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly,
+ findNext, replaceWith, dwFlags, pT->operator HWND());
+ ATLASSERT(m_pFindReplaceDialog != NULL);
+ if(m_pFindReplaceDialog != NULL)
+ m_bFindOnly = bFindOnly;
+ }
+
+ BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/)
+ {
+ T* pT = static_cast<T*>(this);
+
+ // check length first
+ size_t nLen = lstrlen(lpszCompare);
+ LONG nStartChar = 0, nEndChar = 0;
+ // Send EM_GETSEL so we can use both Edit and RichEdit
+ // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)
+ ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
+ if(nLen != (size_t)(nEndChar - nStartChar))
+ return FALSE;
+
+ // length is the same, check contents
+ _CSTRING_NS::CString selectedText;
+ pT->GetSelText(selectedText);
+
+ return (bMatchCase && selectedText.Compare(lpszCompare) == 0) ||
+ (!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0);
+ }
+
+ void TextNotFound(LPCTSTR lpszFind)
+ {
+ T* pT = static_cast<T*>(this);
+ m_bFirstSearch = TRUE;
+ pT->OnTextNotFound(lpszFind);
+ }
+
+ _CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const
+ {
+ _CSTRING_NS::CString text;
+ switch(eItem)
+ {
+ case eText_OnReplaceAllMessage:
+ text = _T("Replaced %d occurances of \"%s\" with \"%s\"");
+ break;
+ case eText_OnReplaceAllTitle:
+ text = _T("Replace All");
+ break;
+ case eText_OnTextNotFoundMessage:
+ text = _T("Unable to find the text \"%s\"");
+ break;
+ case eText_OnTextNotFoundTitle:
+ text = _T("Text not found");
+ break;
+ }
+
+ return text;
+ }
+
+// Overrideable Handlers
+ void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord)
+ {
+ T* pT = static_cast<T*>(this);
+
+ m_sFindNext = lpszFind;
+ m_bMatchCase = bMatchCase;
+ m_bWholeWord = bWholeWord;
+ m_bFindDown = bFindDown;
+
+ if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
+ pT->TextNotFound(m_sFindNext);
+ else
+ pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());
+ }
+
+ void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace)
+ {
+ T* pT = static_cast<T*>(this);
+
+ m_sFindNext = lpszFind;
+ m_sReplaceWith = lpszReplace;
+ m_bMatchCase = bMatchCase;
+ m_bWholeWord = bWholeWord;
+ m_bFindDown = bFindDown;
+
+ if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))
+ pT->ReplaceSel(m_sReplaceWith);
+
+ if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
+ pT->TextNotFound(m_sFindNext);
+ else
+ pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());
+ }
+
+ void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord)
+ {
+ T* pT = static_cast<T*>(this);
+
+ m_sFindNext = lpszFind;
+ m_sReplaceWith = lpszReplace;
+ m_bMatchCase = bMatchCase;
+ m_bWholeWord = bWholeWord;
+ m_bFindDown = TRUE;
+
+ // no selection or different than what looking for
+ if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))
+ {
+ if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
+ {
+ pT->TextNotFound(m_sFindNext);
+ return;
+ }
+ }
+
+ pT->OnReplaceAllCoreBegin();
+
+ int replaceCount=0;
+ do
+ {
+ ++replaceCount;
+ pT->ReplaceSel(m_sReplaceWith);
+ } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown));
+
+ pT->OnReplaceAllCoreEnd(replaceCount);
+ }
+
+ void OnReplaceAllCoreBegin()
+ {
+ T* pT = static_cast<T*>(this);
+
+ m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
+
+ pT->HideSelection(TRUE, FALSE);
+
+ }
+
+ void OnReplaceAllCoreEnd(int replaceCount)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->HideSelection(FALSE, FALSE);
+
+ ::SetCursor(m_hOldCursor);
+
+ _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage);
+ if(message.GetLength() > 0)
+ {
+ _CSTRING_NS::CString formattedMessage;
+ formattedMessage.Format(message,
+ replaceCount, m_sFindNext, m_sReplaceWith);
+ if(m_pFindReplaceDialog != NULL)
+ {
+ m_pFindReplaceDialog->MessageBox(formattedMessage,
+ pT->GetTranslationText(eText_OnReplaceAllTitle),
+ MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ }
+ else
+ {
+ pT->MessageBox(formattedMessage,
+ pT->GetTranslationText(eText_OnReplaceAllTitle),
+ MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ }
+ }
+ }
+
+ void OnTextNotFound(LPCTSTR lpszFind)
+ {
+ T* pT = static_cast<T*>(this);
+ _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage);
+ if(message.GetLength() > 0)
+ {
+ _CSTRING_NS::CString formattedMessage;
+ formattedMessage.Format(message, lpszFind);
+ if(m_pFindReplaceDialog != NULL)
+ {
+ m_pFindReplaceDialog->MessageBox(formattedMessage,
+ pT->GetTranslationText(eText_OnTextNotFoundTitle),
+ MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ }
+ else
+ {
+ pT->MessageBox(formattedMessage,
+ pT->GetTranslationText(eText_OnTextNotFoundTitle),
+ MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ }
+ }
+ else
+ {
+ ::MessageBeep(MB_ICONHAND);
+ }
+ }
+
+ void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/)
+ {
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit
+// based window classes.
+
+// Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit.
+// Example:
+// class CMyEdit : public CWindowImpl<CMyEdit, CEdit>,
+// public CEditFindReplaceImpl<CMyEdit>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyEdit)
+// // your handlers...
+// CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl<CMyEdit>, 1)
+// END_MSG_MAP()
+// // other stuff...
+// };
+
+template <class T, class TFindReplaceDialog = CFindReplaceDialog>
+class CEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>
+{
+protected:
+ typedef CEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;
+ typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;
+
+// Data members
+ LPTSTR m_pShadowBuffer; // Special shadow buffer only used in some cases.
+ UINT m_nShadowSize;
+ int m_bShadowBufferNeeded; // TRUE, FALSE, < 0 => Need to check
+
+public:
+// Constructors
+ CEditFindReplaceImpl() :
+ m_pShadowBuffer(NULL),
+ m_nShadowSize(0),
+ m_bShadowBufferNeeded(-1)
+ {
+ }
+
+ virtual ~CEditFindReplaceImpl()
+ {
+ if(m_pShadowBuffer != NULL)
+ {
+ delete [] m_pShadowBuffer;
+ m_pShadowBuffer = NULL;
+ }
+ }
+
+// Message Handlers
+ BEGIN_MSG_MAP(thisClass)
+ ALT_MSG_MAP(1)
+ CHAIN_MSG_MAP_ALT(baseClass, 1)
+ END_MSG_MAP()
+
+// Operations
+ // Supported only for RichEdit, so this does nothing for Edit
+ void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE)
+ {
+ }
+
+// Operations (overrideable)
+ BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+
+ ATLASSERT(lpszFind != NULL);
+ ATLASSERT(*lpszFind != _T('\0'));
+
+ UINT nLen = pT->GetBufferLength();
+ int nStartChar = 0, nEndChar = 0;
+ pT->GetSel(nStartChar, nEndChar);
+ UINT nStart = nStartChar;
+ int iDir = bFindDown ? +1 : -1;
+
+ // can't find a match before the first character
+ if(nStart == 0 && iDir < 0)
+ return FALSE;
+
+ LPCTSTR lpszText = pT->LockBuffer();
+
+ bool isDBCS = false;
+#ifdef _MBCS
+ CPINFO info = { 0 };
+ ::GetCPInfo(::GetOEMCP(), &info);
+ isDBCS = (info.MaxCharSize > 1);
+#endif
+
+ if(iDir < 0)
+ {
+ // always go back one for search backwards
+ nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));
+ }
+ else if(nStartChar != nEndChar && pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord))
+ {
+ // easy to go backward/forward with SBCS
+#ifndef _UNICODE
+ if(::IsDBCSLeadByte(lpszText[nStart]))
+ nStart++;
+#endif
+ nStart += iDir;
+ }
+
+ // handle search with nStart past end of buffer
+ UINT nLenFind = ::lstrlen(lpszFind);
+ if(nStart + nLenFind - 1 >= nLen)
+ {
+ if(iDir < 0 && nLen >= nLenFind)
+ {
+ if(isDBCS)
+ {
+ // walk back to previous character n times
+ nStart = nLen;
+ int n = nLenFind;
+ while(n--)
+ {
+ nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));
+ }
+ }
+ else
+ {
+ // single-byte character set is easy and fast
+ nStart = nLen - nLenFind;
+ }
+ ATLASSERT(nStart + nLenFind - 1 <= nLen);
+ }
+ else
+ {
+ pT->UnlockBuffer();
+ return FALSE;
+ }
+ }
+
+ // start the search at nStart
+ LPCTSTR lpsz = lpszText + nStart;
+ typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2);
+ CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi;
+
+ if(isDBCS)
+ {
+ // double-byte string search
+ LPCTSTR lpszStop = NULL;
+ if(iDir > 0)
+ {
+ // start at current and find _first_ occurrance
+ lpszStop = lpszText + nLen - nLenFind + 1;
+ }
+ else
+ {
+ // start at top and find _last_ occurrance
+ lpszStop = lpsz;
+ lpsz = lpszText;
+ }
+
+ LPCTSTR lpszFound = NULL;
+ while(lpsz <= lpszStop)
+ {
+#ifndef _UNICODE
+ if(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1])))
+#else
+ if(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1]))
+#endif
+ {
+ LPTSTR lpch = (LPTSTR)(lpsz + nLenFind);
+ TCHAR chSave = *lpch;
+ *lpch = _T('\0');
+ int nResult = (*pfnCompare)(lpsz, lpszFind);
+ *lpch = chSave;
+ if(nResult == 0)
+ {
+ lpszFound = lpsz;
+ if(iDir > 0)
+ break;
+ }
+ }
+ lpsz = ::CharNext(lpsz);
+ }
+ pT->UnlockBuffer();
+
+ if(lpszFound != NULL)
+ {
+ int n = (int)(lpszFound - lpszText);
+ pT->SetSel(n, n + nLenFind);
+ return TRUE;
+ }
+ }
+ else
+ {
+ // single-byte string search
+ UINT nCompare;
+ if(iDir < 0)
+ nCompare = (UINT)(lpsz - lpszText) + 1;
+ else
+ nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1;
+
+ while(nCompare > 0)
+ {
+ ATLASSERT(lpsz >= lpszText);
+ ATLASSERT(lpsz + nLenFind - 1 <= lpszText + nLen - 1);
+
+ LPSTR lpch = (LPSTR)(lpsz + nLenFind);
+ char chSave = *lpch;
+ *lpch = '\0';
+ int nResult = (*pfnCompare)(lpsz, lpszFind);
+ *lpch = chSave;
+ if(nResult == 0)
+ {
+ pT->UnlockBuffer();
+ int n = (int)(lpsz - lpszText);
+ pT->SetSel(n, n + nLenFind);
+ return TRUE;
+ }
+
+ // restore character at end of search
+ *lpch = chSave;
+
+ // move on to next substring
+ nCompare--;
+ lpsz += iDir;
+ }
+ pT->UnlockBuffer();
+ }
+
+ return FALSE;
+ }
+
+ LPCTSTR LockBuffer() const
+ {
+ const T* pT = static_cast<const T*>(this);
+
+ ATLASSERT(pT->m_hWnd != NULL);
+
+ BOOL useShadowBuffer = pT->UseShadowBuffer();
+ if(useShadowBuffer)
+ {
+ if(m_pShadowBuffer == NULL || pT->GetModify())
+ {
+ ATLASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0);
+ UINT nSize = pT->GetWindowTextLength() + 1;
+ if(nSize > m_nShadowSize)
+ {
+ // need more room for shadow buffer
+ T* pThisNoConst = const_cast<T*>(pT);
+ delete[] m_pShadowBuffer;
+ pThisNoConst->m_pShadowBuffer = NULL;
+ pThisNoConst->m_nShadowSize = 0;
+ pThisNoConst->m_pShadowBuffer = new TCHAR[nSize];
+ pThisNoConst->m_nShadowSize = nSize;
+ }
+
+ // update the shadow buffer with GetWindowText
+ ATLASSERT(m_nShadowSize >= nSize);
+ ATLASSERT(m_pShadowBuffer != NULL);
+ pT->GetWindowText(m_pShadowBuffer, nSize);
+ }
+
+ return m_pShadowBuffer;
+ }
+
+ HLOCAL hLocal = pT->GetHandle();
+ ATLASSERT(hLocal != NULL);
+ LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal);
+ ATLASSERT(lpszText != NULL);
+
+ return lpszText;
+ }
+
+ void UnlockBuffer() const
+ {
+ const T* pT = static_cast<const T*>(this);
+
+ ATLASSERT(pT->m_hWnd != NULL);
+
+ BOOL useShadowBuffer = pT->UseShadowBuffer();
+ if(!useShadowBuffer)
+ {
+ HLOCAL hLocal = pT->GetHandle();
+ ATLASSERT(hLocal != NULL);
+ ::LocalUnlock(hLocal);
+ }
+ }
+
+ UINT GetBufferLength() const
+ {
+ const T* pT = static_cast<const T*>(this);
+
+ ATLASSERT(pT->m_hWnd != NULL);
+ UINT nLen = 0;
+ LPCTSTR lpszText = pT->LockBuffer();
+ if(lpszText != NULL)
+ nLen = ::lstrlen(lpszText);
+ pT->UnlockBuffer();
+
+ return nLen;
+ }
+
+ LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const
+ {
+ LPCTSTR lpsz = lpszText + nIndex;
+ LPCTSTR lpszStop = lpszText + nLen;
+ while(lpsz < lpszStop && *lpsz != _T('\r'))
+ ++lpsz;
+ return LONG(lpsz - lpszText);
+ }
+
+ LONG GetSelText(_CSTRING_NS::CString& strText) const
+ {
+ const T* pT = static_cast<const T*>(this);
+
+ int nStartChar = 0, nEndChar = 0;
+ pT->GetSel(nStartChar, nEndChar);
+ ATLASSERT((UINT)nEndChar <= pT->GetBufferLength());
+ LPCTSTR lpszText = pT->LockBuffer();
+ LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar;
+ SecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR));
+ strText.ReleaseBuffer(nLen);
+ pT->UnlockBuffer();
+
+ return nLen;
+ }
+
+ BOOL UseShadowBuffer(void) const
+ {
+ const T* pT = static_cast<const T*>(this);
+
+ if(pT->m_bShadowBufferNeeded < 0)
+ {
+ T* pThisNoConst = const_cast<T*>(pT);
+
+ OSVERSIONINFO ovi = { 0 };
+ ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ ::GetVersionEx(&ovi);
+
+ bool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+ if(bWin9x)
+ {
+ // Windows 95, 98, ME
+ // Under Win9x, it is necessary to maintain a shadow buffer.
+ // It is only updated when the control contents have been changed.
+ pThisNoConst->m_bShadowBufferNeeded = TRUE;
+ }
+ else
+ {
+ // Windows NT, 2000, XP, etc.
+ pThisNoConst->m_bShadowBufferNeeded = FALSE;
+
+#ifndef _UNICODE
+ // On Windows XP (or later), if common controls version 6 is in use
+ // (such as via theming), then EM_GETHANDLE will always return a UNICODE string.
+ // If theming is enabled and Common Controls version 6 is in use,
+ // you're really not suppose to superclass or subclass common controls
+ // with an ANSI windows procedure (so its best to only theme if you use UNICODE).
+ // Using a shadow buffer uses GetWindowText instead, so it solves
+ // this problem for us (although it makes it a little less efficient).
+
+ if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))
+ {
+ // We use DLLVERSIONINFO_private so we don't have to depend on shlwapi.h
+ typedef struct _DLLVERSIONINFO_private
+ {
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+ } DLLVERSIONINFO_private;
+
+ HMODULE hModule = ::LoadLibrary("comctl32.dll");
+ if(hModule != NULL)
+ {
+ typedef HRESULT (CALLBACK *LPFN_DllGetVersion)(DLLVERSIONINFO_private *);
+ LPFN_DllGetVersion fnDllGetVersion = (LPFN_DllGetVersion)::GetProcAddress(hModule, "DllGetVersion");
+ if(fnDllGetVersion != NULL)
+ {
+ DLLVERSIONINFO_private version = { 0 };
+ version.cbSize = sizeof(DLLVERSIONINFO_private);
+ if(SUCCEEDED(fnDllGetVersion(&version)))
+ {
+ if(version.dwMajorVersion >= 6)
+ {
+ pThisNoConst->m_bShadowBufferNeeded = TRUE;
+
+ ATLTRACE2(atlTraceUI, 0, _T("Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later (likely through a manifest file).\r\n"));
+ ATLTRACE2(atlTraceUI, 0, _T("If you use common controls version 6 or later, you should only do so for UNICODE builds.\r\n"));
+ }
+ }
+ }
+
+ ::FreeLibrary(hModule);
+ hModule = NULL;
+ }
+ }
+#endif // !_UNICODE
+ }
+ }
+
+ return (pT->m_bShadowBufferNeeded != FALSE);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl
+// based window classes.
+
+// Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl.
+// Example:
+// class CMyRichEdit : public CWindowImpl<CMyRichEdit, CRichEditCtrl>,
+// public CRichEditFindReplaceImpl<CMyRichEdit>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyRichEdit)
+// // your handlers...
+// CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl<CMyRichEdit>, 1)
+// END_MSG_MAP()
+// // other stuff...
+// };
+
+template <class T, class TFindReplaceDialog = CFindReplaceDialog>
+class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>
+{
+protected:
+ typedef CRichEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;
+ typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;
+
+public:
+ BEGIN_MSG_MAP(thisClass)
+ ALT_MSG_MAP(1)
+ CHAIN_MSG_MAP_ALT(baseClass, 1)
+ END_MSG_MAP()
+
+// Operations (overrideable)
+ BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+
+ ATLASSERT(lpszFind != NULL);
+ FINDTEXTEX ft = { 0 };
+
+ pT->GetSel(ft.chrg);
+ if(m_bFirstSearch)
+ {
+ if(bFindDown)
+ m_nInitialSearchPos = ft.chrg.cpMin;
+ else
+ m_nInitialSearchPos = ft.chrg.cpMax;
+ m_bFirstSearch = FALSE;
+ }
+
+#if (_RICHEDIT_VER >= 0x0200)
+ ft.lpstrText = (LPTSTR)lpszFind;
+#else // !(_RICHEDIT_VER >= 0x0200)
+ USES_CONVERSION;
+ ft.lpstrText = T2A((LPTSTR)lpszFind);
+#endif // !(_RICHEDIT_VER >= 0x0200)
+
+ if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection
+ {
+ if(bFindDown)
+ {
+ ft.chrg.cpMin++;
+ }
+ else
+ {
+ // won't wraparound backwards
+ ft.chrg.cpMin = max(ft.chrg.cpMin, 0);
+ }
+ }
+
+ DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0;
+ dwFlags |= bWholeWord ? FR_WHOLEWORD : 0;
+
+ ft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos;
+
+ if(bFindDown)
+ {
+ if(m_nInitialSearchPos >= 0)
+ ft.chrg.cpMax = pT->GetTextLength();
+
+ dwFlags |= FR_DOWN;
+ ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin);
+ }
+ else
+ {
+ if(m_nInitialSearchPos >= 0)
+ ft.chrg.cpMax = 0;
+
+ dwFlags &= ~FR_DOWN;
+ ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin);
+ }
+
+ BOOL bRet = FALSE;
+
+ if(pT->FindAndSelect(dwFlags, ft) != -1)
+ {
+ bRet = TRUE; // we found the text
+ }
+ else if(m_nInitialSearchPos > 0)
+ {
+ // if the original starting point was not the beginning
+ // of the buffer and we haven't already been here
+ if(bFindDown)
+ {
+ ft.chrg.cpMin = 0;
+ ft.chrg.cpMax = m_nInitialSearchPos;
+ }
+ else
+ {
+ ft.chrg.cpMin = pT->GetTextLength();
+ ft.chrg.cpMax = m_nInitialSearchPos;
+ }
+ m_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength();
+
+ bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE;
+ }
+
+ return bRet;
+ }
+
+ long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft)
+ {
+ T* pT = static_cast<T*>(this);
+ LONG index = pT->FindText(dwFlags, ft);
+ if(index != -1) // i.e. we found something
+ pT->SetSel(ft.chrgText);
+
+ return index;
+ }
+};
+
+}; // namespace WTL
+
+#endif // __ATLFIND_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLFRAME_H__
+#define __ATLFRAME_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlframe.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlframe.h requires atlwin.h to be included first
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CFrameWindowImpl<T, TBase, TWinTraits>
+// CMDIWindow
+// CMDIFrameWindowImpl<T, TBase, TWinTraits>
+// CMDIChildWindowImpl<T, TBase, TWinTraits>
+// COwnerDraw<T>
+// CUpdateUIBase
+// CUpdateUI<T>
+// CDynamicUpdateUI<T>
+// CAutoUpdateUI<T>
+// CDialogResize<T>
+// CDoubleBufferImpl<T>
+// CDoubleBufferWindowImpl<T, TBase, TWinTraits>
+//
+// Global functions:
+// AtlCreateSimpleToolBar()
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CFrameWndClassInfo - Manages frame window Windows class information
+
+class CFrameWndClassInfo
+{
+public:
+#ifndef _WIN32_WCE
+ enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs
+ WNDCLASSEX m_wc;
+#else // CE specific
+ enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string.
+ WNDCLASS m_wc;
+#endif // !_WIN32_WCE
+ LPCTSTR m_lpszOrigName;
+ WNDPROC pWndProc;
+ LPCTSTR m_lpszCursorID;
+ BOOL m_bSystemCursor;
+ ATOM m_atom;
+ TCHAR m_szAutoName[cchAutoName];
+ UINT m_uCommonResourceID;
+
+#ifndef _WIN32_WCE
+ ATOM Register(WNDPROC* pProc)
+ {
+ if (m_atom == 0)
+ {
+ CWindowCreateCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(m_atom == 0)
+ {
+ HINSTANCE hInst = ModuleHelper::GetModuleInstance();
+
+ if (m_lpszOrigName != NULL)
+ {
+ ATLASSERT(pProc != NULL);
+ LPCTSTR lpsz = m_wc.lpszClassName;
+ WNDPROC proc = m_wc.lpfnWndProc;
+
+ WNDCLASSEX wc = { 0 };
+ wc.cbSize = sizeof(WNDCLASSEX);
+ // try process local class first
+ if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
+ {
+ // try global class
+ if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))
+ {
+ lock.Unlock();
+ return 0;
+ }
+ }
+ m_wc = wc;
+ pWndProc = m_wc.lpfnWndProc;
+ m_wc.lpszClassName = lpsz;
+ m_wc.lpfnWndProc = proc;
+ }
+ else
+ {
+ m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
+ }
+
+ m_wc.hInstance = hInst;
+ m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
+ if (m_wc.lpszClassName == NULL)
+ {
+#if (_WIN32_WINNT >= 0x0500) || defined(_WIN64)
+ SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc);
+#else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
+ SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
+#endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
+ m_wc.lpszClassName = m_szAutoName;
+ }
+
+ WNDCLASSEX wcTemp = m_wc;
+ m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
+ if (m_atom == 0)
+ {
+ if(m_uCommonResourceID != 0) // use it if not zero
+ {
+ m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+ m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+ }
+ m_atom = ::RegisterClassEx(&m_wc);
+ }
+ }
+
+ lock.Unlock();
+ }
+
+ if (m_lpszOrigName != NULL)
+ {
+ ATLASSERT(pProc != NULL);
+ ATLASSERT(pWndProc != NULL);
+ *pProc = pWndProc;
+ }
+
+ return m_atom;
+ }
+#else // CE specific
+ ATOM Register(WNDPROC* pProc)
+ {
+ if (m_atom == 0)
+ {
+ CWindowCreateCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
+ ATLASSERT(FALSE);
+ return 0;
+ }
+
+ if(m_atom == 0)
+ {
+ HINSTANCE hInst = ModuleHelper::GetModuleInstance();
+
+ if (m_lpszOrigName != NULL)
+ {
+ ATLASSERT(pProc != NULL);
+ LPCTSTR lpsz = m_wc.lpszClassName;
+ WNDPROC proc = m_wc.lpfnWndProc;
+
+ WNDCLASS wc = { 0 };
+ // try process local class first
+ if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
+ {
+ // try global class
+ if(!::GetClassInfo(NULL, m_lpszOrigName, &wc))
+ {
+ lock.Unlock();
+ return 0;
+ }
+ }
+ m_wc = wc;
+ pWndProc = m_wc.lpfnWndProc;
+ m_wc.lpszClassName = lpsz;
+ m_wc.lpfnWndProc = proc;
+ }
+ else
+ {
+#if defined(GWES_CURSOR) || defined(GWES_MCURSOR)
+ m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
+#else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
+ m_wc.hCursor = NULL;
+#endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
+ }
+
+ m_wc.hInstance = hInst;
+ m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
+ if (m_wc.lpszClassName == NULL)
+ {
+ wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
+ m_wc.lpszClassName = m_szAutoName;
+ }
+
+ WNDCLASS wcTemp = m_wc;
+ m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
+ if (m_atom == 0)
+ {
+ if(m_uCommonResourceID != 0) // use it if not zero
+ m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+ m_atom = ::RegisterClass(&m_wc);
+ }
+ }
+
+ lock.Unlock();
+ }
+
+ if (m_lpszOrigName != NULL)
+ {
+ ATLASSERT(pProc != NULL);
+ ATLASSERT(pWndProc != NULL);
+ *pProc = pWndProc;
+ }
+
+ return m_atom;
+ }
+#endif // _WIN32_WCE
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Macros for declaring frame window WNDCLASS
+
+#ifndef _WIN32_WCE
+
+#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { sizeof(WNDCLASSEX), 0, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { sizeof(WNDCLASSEX), style, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { sizeof(WNDCLASSEX), 0, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
+ OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#else // CE specific
+
+#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { 0, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { style, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
+static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+{ \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { NULL, StartWindowProc, \
+ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \
+ OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+}
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFrameWindowImpl
+
+// Client window command chaining macro (only for frame windows)
+#define CHAIN_CLIENT_COMMANDS() \
+ if(uMsg == WM_COMMAND && m_hWndClient != NULL) \
+ ::SendMessage(m_hWndClient, uMsg, wParam, lParam);
+
+// standard toolbar styles
+#define ATL_SIMPLE_TOOLBAR_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)
+// toolbar in a rebar pane
+#define ATL_SIMPLE_TOOLBAR_PANE_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)
+// standard rebar styles
+#if (_WIN32_IE >= 0x0400)
+ #define ATL_SIMPLE_REBAR_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)
+#else
+ #define ATL_SIMPLE_REBAR_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS)
+#endif // !(_WIN32_IE >= 0x0400)
+// rebar without borders
+#if (_WIN32_IE >= 0x0400)
+ #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)
+#else
+ #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
+ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER)
+#endif // !(_WIN32_IE >= 0x0400)
+
+// command bar support
+#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
+
+#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
+#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
+#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
+
+struct _AtlFrameWnd_CmdBarPopupMenu
+{
+ int cbSize;
+ HMENU hMenu;
+ UINT uFlags;
+ int x;
+ int y;
+ LPTPMPARAMS lptpm;
+};
+
+#define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu
+
+#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
+
+
+template <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
+class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits >
+{
+public:
+ DECLARE_FRAME_WND_CLASS(NULL, 0)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ struct _ChevronMenuInfo
+ {
+ HMENU hMenu;
+ LPNMREBARCHEVRON lpnm;
+ bool bCmdBar;
+ };
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+
+// Data members
+ HWND m_hWndToolBar;
+ HWND m_hWndStatusBar;
+ HWND m_hWndClient;
+
+#ifdef _WIN32_WCE
+ HWND m_hWndCECommandBar;
+#endif // _WIN32_WCE
+
+ HACCEL m_hAccel;
+
+// Constructor
+ CFrameWindowImplBase() :
+ m_hWndToolBar(NULL),
+ m_hWndStatusBar(NULL),
+ m_hWndClient(NULL),
+#ifdef _WIN32_WCE
+ m_hWndCECommandBar(NULL),
+#endif // _WIN32_WCE
+ m_hAccel(NULL)
+ { }
+
+// Methods
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
+ {
+ ATLASSERT(m_hWnd == NULL);
+
+ if(atom == 0)
+ return NULL;
+
+ ModuleHelper::AddCreateWndData(&m_thunk.cd, this);
+
+ if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD))
+ MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
+ if(rect.m_lpRect == NULL)
+ rect.m_lpRect = &TBase::rcDefault;
+
+ HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,
+ dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,
+ rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,
+ ModuleHelper::GetModuleInstance(), lpCreateParam);
+
+ ATLASSERT(hWnd == NULL || m_hWnd == hWnd);
+
+ return hWnd;
+ }
+
+ static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
+ DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ HINSTANCE hInst = ModuleHelper::GetResourceInstance();
+ HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);
+ if (hRsrc == NULL)
+ return NULL;
+
+ HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
+ if (hGlobal == NULL)
+ return NULL;
+
+ _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);
+ if (pData == NULL)
+ return NULL;
+ ATLASSERT(pData->wVersion == 1);
+
+ WORD* pItems = pData->items();
+ int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);
+ CTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ TBBUTTON* pTBBtn = buff.Allocate(nItems);
+ ATLASSERT(pTBBtn != NULL);
+ if(pTBBtn == NULL)
+ return NULL;
+
+ const int cxSeparator = 8;
+
+ // set initial separator (half width)
+ if(bInitialSeparator)
+ {
+ pTBBtn[0].iBitmap = cxSeparator / 2;
+ pTBBtn[0].idCommand = 0;
+ pTBBtn[0].fsState = 0;
+ pTBBtn[0].fsStyle = TBSTYLE_SEP;
+ pTBBtn[0].dwData = 0;
+ pTBBtn[0].iString = 0;
+ }
+
+ int nBmp = 0;
+ for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)
+ {
+ if(pItems[i] != 0)
+ {
+ pTBBtn[j].iBitmap = nBmp++;
+ pTBBtn[j].idCommand = pItems[i];
+ pTBBtn[j].fsState = TBSTATE_ENABLED;
+ pTBBtn[j].fsStyle = TBSTYLE_BUTTON;
+ pTBBtn[j].dwData = 0;
+ pTBBtn[j].iString = 0;
+ }
+ else
+ {
+ pTBBtn[j].iBitmap = cxSeparator;
+ pTBBtn[j].idCommand = 0;
+ pTBBtn[j].fsState = 0;
+ pTBBtn[j].fsStyle = TBSTYLE_SEP;
+ pTBBtn[j].dwData = 0;
+ pTBBtn[j].iString = 0;
+ }
+ }
+
+#ifndef _WIN32_WCE
+ HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
+ if(hWnd == NULL)
+ {
+ ATLASSERT(FALSE);
+ return NULL;
+ }
+#else // CE specific
+ dwStyle;
+ nID;
+ // The toolbar must go onto the existing CommandBar or MenuBar
+ HWND hWnd = hWndParent;
+#endif // _WIN32_WCE
+
+ ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);
+
+ // check if font is taller than our bitmaps
+ CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
+ if(font.IsNull())
+ font = (HFONT)::GetStockObject(SYSTEM_FONT);
+ LOGFONT lf = { 0 };
+ font.GetLogFont(lf);
+ WORD cyFontHeight = (WORD)abs(lf.lfHeight);
+
+#ifndef _WIN32_WCE
+ WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID);
+ if(bitsPerPixel > 4)
+ {
+ COLORREF crMask = CLR_DEFAULT;
+ if(bitsPerPixel == 32)
+ {
+ // 32-bit color bitmap with alpha channel (valid for Windows XP and later)
+ crMask = CLR_NONE;
+ }
+ HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+ ATLASSERT(hImageList != NULL);
+ ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList);
+ }
+ else
+#endif // !_WIN32_WCE
+ {
+ TBADDBITMAP tbab = { 0 };
+ tbab.hInst = hInst;
+ tbab.nID = nResourceID;
+ ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);
+ }
+
+ ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);
+ ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, max(pData->wHeight, cyFontHeight)));
+ const int cxyButtonMargin = 7;
+ ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, max(pData->wHeight, cyFontHeight) + cxyButtonMargin));
+
+ return hWnd;
+ }
+
+#ifndef _WIN32_WCE
+ static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ // Ensure style combinations for proper rebar painting
+ if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER)
+ dwStyle &= ~WS_BORDER;
+ else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))
+ dwStyle |= CCS_NODIVIDER;
+
+ // Create rebar window
+ HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
+ if(hWndReBar == NULL)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n"));
+ return NULL;
+ }
+
+ // Initialize and send the REBARINFO structure
+ REBARINFO rbi = { 0 };
+ rbi.cbSize = sizeof(REBARINFO);
+ rbi.fMask = 0;
+ if(!::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n"));
+ ::DestroyWindow(hWndReBar);
+ return NULL;
+ }
+
+ return hWndReBar;
+ }
+
+ BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ ATLASSERT(!::IsWindow(m_hWndToolBar));
+ m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID);
+ return (m_hWndToolBar != NULL);
+ }
+
+ static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
+ {
+ ATLASSERT(::IsWindow(hWndReBar)); // must be already created
+#ifdef _DEBUG
+ // block - check if this is really a rebar
+ {
+ TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 };
+ ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));
+ ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);
+ }
+#endif // _DEBUG
+ ATLASSERT(::IsWindow(hWndBand)); // must be already created
+
+ // Get number of buttons on the toolbar
+ int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);
+
+ // Set band info structure
+ REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
+#if (_WIN32_IE >= 0x0400)
+ rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;
+#else
+ rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE;
+#endif // !(_WIN32_IE >= 0x0400)
+ if(lpstrTitle != NULL)
+ rbBand.fMask |= RBBIM_TEXT;
+ rbBand.fStyle = RBBS_CHILDEDGE;
+#if (_WIN32_IE >= 0x0500)
+ if(nBtnCount > 0) // add chevron style for toolbar with buttons
+ rbBand.fStyle |= RBBS_USECHEVRON;
+#endif // (_WIN32_IE >= 0x0500)
+ if(bNewRow)
+ rbBand.fStyle |= RBBS_BREAK;
+
+ rbBand.lpText = (LPTSTR)lpstrTitle;
+ rbBand.hwndChild = hWndBand;
+ if(nID == 0) // calc band ID
+ nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
+ rbBand.wID = nID;
+
+ // Calculate the size of the band
+ BOOL bRet = FALSE;
+ RECT rcTmp = { 0 };
+ if(nBtnCount > 0)
+ {
+ bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);
+ ATLASSERT(bRet);
+ rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;
+ rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
+ if(bFullWidthAlways)
+ {
+ rbBand.cxMinChild = rbBand.cx;
+ }
+ else if(lpstrTitle == NULL)
+ {
+ bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);
+ ATLASSERT(bRet);
+ rbBand.cxMinChild = rcTmp.right;
+ }
+ else
+ {
+ rbBand.cxMinChild = 0;
+ }
+ }
+ else // no buttons, either not a toolbar or really has no buttons
+ {
+ bRet = ::GetWindowRect(hWndBand, &rcTmp);
+ ATLASSERT(bRet);
+ rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);
+ rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0;
+ rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ rbBand.cxIdeal = rbBand.cx;
+#endif // (_WIN32_IE >= 0x0400)
+
+ // Add the band
+ LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
+ if(lRes == 0)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n"));
+ return FALSE;
+ }
+
+#if (_WIN32_IE >= 0x0501)
+ DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L);
+ ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS);
+#endif // (_WIN32_IE >= 0x0501)
+
+ return TRUE;
+ }
+
+ BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
+ ATLASSERT(::IsWindow(hWndBand)); // must be created
+ return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);
+ }
+
+#if (_WIN32_IE >= 0x0400)
+ void SizeSimpleReBarBands()
+ {
+ ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
+
+ int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);
+
+ for(int i = 0; i < nCount; i++)
+ {
+ REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
+ rbBand.fMask = RBBIM_SIZE;
+ BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);
+ ATLASSERT(bRet);
+ RECT rect = { 0, 0, 0, 0 };
+ ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);
+ rbBand.cx += rect.left + rect.right;
+ bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);
+ ATLASSERT(bRet);
+ }
+ }
+#endif // (_WIN32_IE >= 0x0400)
+#endif // _WIN32_WCE
+
+#ifndef _WIN32_WCE
+ BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
+#else // CE specific
+ BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
+#endif // _WIN32_WCE
+ {
+ ATLASSERT(!::IsWindow(m_hWndStatusBar));
+ m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);
+ return (m_hWndStatusBar != NULL);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
+#else // CE specific
+ BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
+#endif // _WIN32_WCE
+ {
+ const int cchMax = 128; // max text length is 127 for status bars (+1 for null)
+ TCHAR szText[cchMax];
+ szText[0] = 0;
+ ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
+ return CreateSimpleStatusBar(szText, dwStyle, nID);
+ }
+
+#ifdef _WIN32_WCE
+ BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1)
+ {
+ ATLASSERT(m_hWndCECommandBar == NULL);
+ ATLASSERT(m_hWndToolBar == NULL);
+
+ m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID);
+ if(m_hWndCECommandBar == NULL)
+ return FALSE;
+
+ m_hWndToolBar = m_hWndCECommandBar;
+
+ BOOL bRet = TRUE;
+
+ if(pszMenu != NULL)
+ bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton);
+
+ bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0);
+
+ return bRet;
+ }
+
+#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+ BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0)
+ {
+ ATLASSERT(m_hWndCECommandBar == NULL);
+
+ SHMENUBARINFO mbi = { 0 };
+ mbi.cbSize = sizeof(mbi);
+ mbi.hwndParent = m_hWnd;
+ mbi.dwFlags = dwFlags;
+ mbi.nToolBarId = nToolBarId;
+ mbi.hInstRes = ModuleHelper::GetResourceInstance();
+ mbi.nBmpId = nBmpId;
+ mbi.cBmpImages = cBmpImages;
+ mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar
+
+ BOOL bRet = ::SHCreateMenuBar(&mbi);
+ if(bRet != FALSE)
+ {
+ m_hWndCECommandBar = mbi.hwndMB;
+ SizeToMenuBar();
+ }
+
+ return bRet;
+ }
+
+ void SizeToMenuBar() // for menu bar only
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(::IsWindow(m_hWndCECommandBar));
+
+ RECT rect = { 0 };
+ GetWindowRect(&rect);
+ RECT rectMB = { 0 };
+ ::GetWindowRect(m_hWndCECommandBar, &rectMB);
+ int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top;
+ SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE);
+ }
+#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
+#endif // _WIN32_WCE
+
+ void UpdateLayout(BOOL bResizeBars = TRUE)
+ {
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+
+ // position bars and offset their dimensions
+ UpdateBarsPosition(rect, bResizeBars);
+
+ // resize client window
+ if(m_hWndClient != NULL)
+ ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
+ {
+ // resize toolbar
+ if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
+ {
+ if(bResizeBars != FALSE)
+ {
+ ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
+ ::InvalidateRect(m_hWndToolBar, NULL, TRUE);
+ }
+ RECT rectTB = { 0 };
+ ::GetWindowRect(m_hWndToolBar, &rectTB);
+ rect.top += rectTB.bottom - rectTB.top;
+ }
+
+ // resize status bar
+ if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
+ {
+ if(bResizeBars != FALSE)
+ ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
+ RECT rectSB = { 0 };
+ ::GetWindowRect(m_hWndStatusBar, &rectSB);
+ rect.bottom -= rectSB.bottom - rectSB.top;
+ }
+ }
+
+ BOOL PreTranslateMessage(MSG* pMsg)
+ {
+ if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
+ return TRUE;
+ return FALSE;
+ }
+
+ BEGIN_MSG_MAP(CFrameWindowImplBase)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+#ifndef _WIN32_WCE
+ NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)
+ NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)
+#endif // !_WIN32_WCE
+ END_MSG_MAP()
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_hWndClient != NULL) // view will paint itself instead
+ return 1;
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+
+ if(m_hWndStatusBar == NULL)
+ return 1;
+
+ WORD wFlags = HIWORD(wParam);
+ if(wFlags == 0xFFFF && lParam == NULL) // menu closing
+ {
+ ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);
+ }
+ else
+ {
+ const int cchBuff = 256;
+ TCHAR szBuff[cchBuff];
+ szBuff[0] = 0;
+ if(!(wFlags & MF_POPUP))
+ {
+ WORD wID = LOWORD(wParam);
+ // check for special cases
+ if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs
+ wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);
+ else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items
+ wID = ATL_IDS_MRU_FILE;
+ else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows
+ wID = ATL_IDS_MDICHILD;
+
+ int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff);
+ for(int i = 0; i < nRet; i++)
+ {
+ if(szBuff[i] == _T('\n'))
+ {
+ szBuff[i] = 0;
+ break;
+ }
+ }
+ }
+ ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);
+ ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);
+ }
+
+ return 1;
+ }
+#endif // !_WIN32_WCE
+
+ LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)
+ {
+ if(m_hWndClient != NULL)
+ ::SetFocus(m_hWndClient);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
+ {
+ if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0)
+ ::PostQuitMessage(1);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;
+ pDispInfo->szText[0] = 0;
+
+ if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
+ {
+ const int cchBuff = 256;
+ char szBuff[cchBuff];
+ szBuff[0] = 0;
+ int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
+ for(int i = 0; i < nRet; i++)
+ {
+ if(szBuff[i] == '\n')
+ {
+ SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
+ break;
+ }
+ }
+#if (_WIN32_IE >= 0x0300)
+ if(nRet > 0) // string was loaded, save it
+ pDispInfo->uFlags |= TTF_DI_SETITEM;
+#endif // (_WIN32_IE >= 0x0300)
+ }
+
+ return 0;
+ }
+
+ LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
+ {
+ LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;
+ pDispInfo->szText[0] = 0;
+
+ if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
+ {
+ const int cchBuff = 256;
+ wchar_t szBuff[cchBuff];
+ szBuff[0] = 0;
+ int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
+ for(int i = 0; i < nRet; i++)
+ {
+ if(szBuff[i] == L'\n')
+ {
+ SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
+ break;
+ }
+ }
+#if (_WIN32_IE >= 0x0300)
+ if(nRet > 0) // string was loaded, save it
+ pDispInfo->uFlags |= TTF_DI_SETITEM;
+#endif // (_WIN32_IE >= 0x0300)
+ }
+
+ return 0;
+ }
+#endif // !_WIN32_WCE
+
+// Implementation - chevron menu support
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ bool PrepareChevronMenu(_ChevronMenuInfo& cmi)
+ {
+ // get rebar and toolbar
+ REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };
+ rbbi.fMask = RBBIM_CHILD;
+ BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
+ ATLASSERT(bRet);
+
+ // assume the band is a toolbar
+ ATL::CWindow wnd = rbbi.hwndChild;
+ int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
+ if(nCount <= 0) // probably not a toolbar
+ return false;
+
+ // check if it's a command bar
+ CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
+ cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);
+
+ // build a menu from hidden items
+ CMenuHandle menu;
+ bRet = menu.CreatePopupMenu();
+ ATLASSERT(bRet);
+ RECT rcClient = { 0 };
+ bRet = wnd.GetClientRect(&rcClient);
+ ATLASSERT(bRet);
+ for(int i = 0; i < nCount; i++)
+ {
+ TBBUTTON tbb = { 0 };
+ bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
+ ATLASSERT(bRet);
+ // skip hidden buttons
+ if((tbb.fsState & TBSTATE_HIDDEN) != 0)
+ continue;
+ RECT rcButton = { 0 };
+ bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
+ ATLASSERT(bRet);
+ bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
+ if(rcButton.right > rcClient.right)
+ {
+ if(tbb.fsStyle & BTNS_SEP)
+ {
+ if(menu.GetMenuItemCount() > 0)
+ menu.AppendMenu(MF_SEPARATOR);
+ }
+ else if(cmi.bCmdBar)
+ {
+ const int cchBuff = 200;
+ TCHAR szBuff[cchBuff] = { 0 };
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
+ mii.dwTypeData = szBuff;
+ mii.cch = cchBuff;
+ bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
+ ATLASSERT(bRet);
+ // Note: CmdBar currently supports only drop-down items
+ ATLASSERT(::IsMenu(mii.hSubMenu));
+ bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
+ ATLASSERT(bRet);
+ }
+ else
+ {
+ // get button's text
+ const int cchBuff = 200;
+ TCHAR szBuff[cchBuff] = { 0 };
+ LPTSTR lpstrText = szBuff;
+ TBBUTTONINFO tbbi = { 0 };
+ tbbi.cbSize = sizeof(TBBUTTONINFO);
+ tbbi.dwMask = TBIF_TEXT;
+ tbbi.pszText = szBuff;
+ tbbi.cchText = cchBuff;
+ if(wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1 || lstrlen(szBuff) == 0)
+ {
+ // no text for this button, try a resource string
+ lpstrText = _T("");
+ int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff);
+ for(int n = 0; n < nRet; n++)
+ {
+ if(szBuff[n] == _T('\n'))
+ {
+ lpstrText = &szBuff[n + 1];
+ break;
+ }
+ }
+ }
+ bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
+ ATLASSERT(bRet);
+ }
+ }
+ }
+
+ if(menu.GetMenuItemCount() == 0) // no hidden buttons after all
+ {
+ menu.DestroyMenu();
+ ::MessageBeep((UINT)-1);
+ return false;
+ }
+
+ cmi.hMenu = menu;
+ return true;
+ }
+
+ void DisplayChevronMenu(_ChevronMenuInfo& cmi)
+ {
+#ifndef TPM_VERPOSANIMATION
+ const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag
+#endif
+ // convert chevron rect to screen coordinates
+ ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
+ POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom };
+ wndFrom.MapWindowPoints(NULL, &pt, 1);
+ RECT rc = cmi.lpnm->rc;
+ wndFrom.MapWindowPoints(NULL, &rc);
+ // set up flags and rect
+ UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
+ TPMPARAMS TPMParams = { 0 };
+ TPMParams.cbSize = sizeof(TPMPARAMS);
+ TPMParams.rcExclude = rc;
+ // check if this window has a command bar
+ HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
+ if(::IsWindow(hWndCmdBar))
+ {
+ CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams };
+ ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
+ }
+ else
+ {
+ CMenuHandle menu = cmi.hMenu;
+ menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams);
+ }
+ }
+
+ void CleanupChevronMenu(_ChevronMenuInfo& cmi)
+ {
+ CMenuHandle menu = cmi.hMenu;
+ // if menu is from a command bar, detach submenus so they are not destroyed
+ if(cmi.bCmdBar)
+ {
+ for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
+ menu.RemoveMenu(i, MF_BYPOSITION);
+ }
+ // destroy menu
+ menu.DestroyMenu();
+ // convert chevron rect to screen coordinates
+ ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
+ RECT rc = cmi.lpnm->rc;
+ wndFrom.MapWindowPoints(NULL, &rc);
+ // eat next message if click is on the same button
+ MSG msg = { 0 };
+ if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt))
+ ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+};
+
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
+class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >
+{
+public:
+ HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
+ {
+ ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
+
+ dwStyle = T::GetWndStyle(dwStyle);
+ dwExStyle = T::GetWndExStyle(dwExStyle);
+
+ if(rect.m_lpRect == NULL)
+ rect.m_lpRect = &TBase::rcDefault;
+
+ return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
+ }
+
+ HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
+ {
+ const int cchName = 256;
+ TCHAR szWindowName[cchName];
+ szWindowName[0] = 0;
+#ifndef _WIN32_WCE
+ ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
+ HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
+#else // CE specific
+ ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
+
+ // This always needs to be NULL for Windows CE.
+ // Frame Window menus have to go onto the CommandBar.
+ // Use CreateSimpleCECommandBar
+ HMENU hMenu = NULL;
+#endif // _WIN32_WCE
+
+ T* pT = static_cast<T*>(this);
+ HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
+
+ if(hWnd != NULL)
+ m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
+
+ return hWnd;
+ }
+
+ BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ if(nResourceID == 0)
+ nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
+#ifndef _WIN32_WCE
+ ATLASSERT(!::IsWindow(m_hWndToolBar));
+ m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
+ return (m_hWndToolBar != NULL);
+#else // CE specific
+ HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
+ return (hWnd != NULL);
+#endif // _WIN32_WCE
+ }
+
+#ifdef _WIN32_WCE
+ // CE specific variant that returns the handle of the toolbar
+ HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ if(nResourceID == 0)
+ nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
+
+ return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
+ }
+#endif // _WIN32_WCE
+
+// message map and handlers
+ typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass;
+
+ BEGIN_MSG_MAP(CFrameWindowImpl)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
+#endif // (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+#endif // !_ATL_NO_REBAR_SUPPORT
+ CHAIN_MSG_MAP(_baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam != SIZE_MINIMIZED)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout(FALSE);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+ LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
+ if(!pT->PrepareChevronMenu(cmi))
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+ // display a popup menu with hidden items
+ pT->DisplayChevronMenu(cmi);
+ // cleanup
+ pT->CleanupChevronMenu(cmi);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
+#endif // !_ATL_NO_REBAR_SUPPORT
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AtlCreateSimpleToolBar - helper for creating simple toolbars
+
+#ifndef _WIN32_WCE
+
+inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
+ DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+{
+ return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID);
+}
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMDIWindow
+
+#ifndef _WIN32_WCE
+
+#ifndef _WTL_MDIWINDOWMENU_TEXT
+#define _WTL_MDIWINDOWMENU_TEXT _T("&Window")
+#endif
+
+class CMDIWindow : public ATL::CWindow
+{
+public:
+// Data members
+ HWND m_hWndMDIClient;
+ HMENU m_hMenu;
+
+// Constructors
+ CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL)
+ { }
+
+ CMDIWindow& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// Operations
+ HWND MDIGetActive(BOOL* lpbMaximized = NULL)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);
+ }
+
+ void MDIActivate(HWND hWndChildToActivate)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ATLASSERT(::IsWindow(hWndChildToActivate));
+ ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);
+ }
+
+ void MDINext(HWND hWndChild, BOOL bPrevious = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild));
+ ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);
+ }
+
+ void MDIMaximize(HWND hWndChildToMaximize)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ATLASSERT(::IsWindow(hWndChildToMaximize));
+ ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);
+ }
+
+ void MDIRestore(HWND hWndChildToRestore)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ATLASSERT(::IsWindow(hWndChildToRestore));
+ ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);
+ }
+
+ void MDIDestroy(HWND hWndChildToDestroy)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ATLASSERT(::IsWindow(hWndChildToDestroy));
+ ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);
+ }
+
+ BOOL MDICascade(UINT uFlags = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);
+ }
+
+ BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);
+ }
+
+ void MDIIconArrange()
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
+ }
+
+ HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);
+ }
+
+ HMENU MDIRefreshMenu()
+ {
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+ return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
+ }
+
+// Additional operations
+ static HMENU GetStandardWindowMenu(HMENU hMenu)
+ {
+ int nCount = ::GetMenuItemCount(hMenu);
+ if(nCount == -1)
+ return NULL;
+ int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
+ if(nLen == 0)
+ return NULL;
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpszText = buff.Allocate(nLen + 1);
+ if(lpszText == NULL)
+ return NULL;
+ if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
+ return NULL;
+ if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0)
+ return NULL;
+ return ::GetSubMenu(hMenu, nCount - 2);
+ }
+
+ void SetMDIFrameMenu()
+ {
+ HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);
+ MDISetMenu(m_hMenu, hWindowMenu);
+ MDIRefreshMenu();
+ ::DrawMenuBar(GetMDIFrame());
+ }
+
+ HWND GetMDIFrame() const
+ {
+ return ::GetParent(m_hWndMDIClient);
+ }
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMDIFrameWindowImpl
+
+#ifndef _WIN32_WCE
+
+// MDI child command chaining macro (only for MDI frame windows)
+#define CHAIN_MDI_CHILD_COMMANDS() \
+ if(uMsg == WM_COMMAND) \
+ { \
+ HWND hWndChild = MDIGetActive(); \
+ if(hWndChild != NULL) \
+ ::SendMessage(hWndChild, uMsg, wParam, lParam); \
+ }
+
+template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
+class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
+{
+public:
+ HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
+ {
+ m_hMenu = hMenu;
+ ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
+
+ dwStyle = T::GetWndStyle(dwStyle);
+ dwExStyle = T::GetWndExStyle(dwExStyle);
+
+ if(rect.m_lpRect == NULL)
+ rect.m_lpRect = &TBase::rcDefault;
+
+ return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
+ }
+
+ HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
+ {
+ const int cchName = 256;
+ TCHAR szWindowName[cchName];
+ szWindowName[0] = 0;
+ ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
+ HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
+
+ T* pT = static_cast<T*>(this);
+ HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
+
+ if(hWnd != NULL)
+ m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
+
+ return hWnd;
+ }
+
+ BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ ATLASSERT(!::IsWindow(m_hWndToolBar));
+ if(nResourceID == 0)
+ nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
+ m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
+ return (m_hWndToolBar != NULL);
+ }
+
+ virtual WNDPROC GetWindowProc()
+ {
+ return MDIFrameWindowProc;
+ }
+
+ static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;
+ // set a ptr to this message and save the old value
+#if (_ATL_VER >= 0x0700)
+ ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
+ const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
+#else // !(_ATL_VER >= 0x0700)
+ MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
+ const MSG* pOldMsg = pThis->m_pCurrentMsg;
+#endif // !(_ATL_VER >= 0x0700)
+ pThis->m_pCurrentMsg = &msg;
+ // pass to the message map to process
+ LRESULT lRes = 0;
+ 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);
+#if (_ATL_VER >= 0x0700)
+ // mark window as destryed
+ pThis->m_dwState |= WINSTATE_DESTROYED;
+#else // !(_ATL_VER >= 0x0700)
+ // clear out window handle
+ HWND hWnd = pThis->m_hWnd;
+ pThis->m_hWnd = NULL;
+ // clean up after window is destroyed
+ pThis->OnFinalMessage(hWnd);
+#endif // !(_ATL_VER >= 0x0700)
+ }
+ }
+#if (_ATL_VER >= 0x0700)
+ if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL)
+ {
+ // clear out window handle
+ HWND hWnd = pThis->m_hWnd;
+ pThis->m_hWnd = NULL;
+ pThis->m_dwState &= ~WINSTATE_DESTROYED;
+ // clean up after window is destroyed
+ pThis->OnFinalMessage(hWnd);
+ }
+#endif // (_ATL_VER >= 0x0700)
+ return lRes;
+ }
+
+ // Overriden to call DefWindowProc which uses DefFrameProc
+ 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)
+ {
+ return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam);
+ }
+
+ BOOL PreTranslateMessage(MSG* pMsg)
+ {
+ if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))
+ return TRUE;
+ return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg);
+ }
+
+ HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
+ {
+ DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
+ DWORD dwExStyle = WS_EX_CLIENTEDGE;
+
+ CLIENTCREATESTRUCT ccs = { 0 };
+ ccs.hWindowMenu = hWindowMenu;
+ ccs.idFirstChild = nFirstChildID;
+
+ if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)
+ {
+ // parent MDI frame's scroll styles move to the MDICLIENT
+ dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL));
+
+ // fast way to turn off the scrollbar bits (without a resize)
+ ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);
+ }
+
+ // Create MDICLIENT window
+ m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL,
+ dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID),
+ ModuleHelper::GetModuleInstance(), (LPVOID)&ccs);
+ if (m_hWndClient == NULL)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n"));
+ return NULL;
+ }
+
+ // Move it to the top of z-order
+ ::BringWindowToTop(m_hWndClient);
+
+ // set as MDI client window
+ m_hWndMDIClient = m_hWndClient;
+
+ // update to proper size
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+
+ return m_hWndClient;
+ }
+
+ typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
+
+ BEGIN_MSG_MAP(CMDIFrameWindowImpl)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
+#endif // (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0500)
+ NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_ATL_NO_REBAR_SUPPORT
+ CHAIN_MSG_MAP(_baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(wParam != SIZE_MINIMIZED)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+ // message must be handled, otherwise DefFrameProc would resize the client again
+ return 0;
+ }
+
+ LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ // don't allow CFrameWindowImplBase to handle this one
+ return DefWindowProc(uMsg, wParam, lParam);
+ }
+
+ LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ SetMDIFrameMenu();
+ return 0;
+ }
+
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout(FALSE);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500)
+ LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
+ if(!pT->PrepareChevronMenu(cmi))
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+ // display a popup menu with hidden items
+ pT->DisplayChevronMenu(cmi);
+ // cleanup
+ pT->CleanupChevronMenu(cmi);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_ATL_NO_REBAR_SUPPORT
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMDIChildWindowImpl
+
+#ifndef _WIN32_WCE
+
+template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>
+class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
+{
+public:
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ UINT nMenuID = 0, LPVOID lpCreateParam = NULL)
+ {
+ ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
+
+ if(nMenuID != 0)
+ m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID));
+
+ dwStyle = T::GetWndStyle(dwStyle);
+ dwExStyle = T::GetWndExStyle(dwExStyle);
+
+ dwExStyle |= WS_EX_MDICHILD; // force this one
+ m_pfnSuperWindowProc = ::DefMDIChildProc;
+ m_hWndMDIClient = hWndParent;
+ ATLASSERT(::IsWindow(m_hWndMDIClient));
+
+ if(rect.m_lpRect == NULL)
+ rect.m_lpRect = &TBase::rcDefault;
+
+ // If the currently active MDI child is maximized, we want to create this one maximized too
+ ATL::CWindow wndParent = hWndParent;
+ BOOL bMaximized = FALSE;
+ wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
+ if(bMaximized)
+ wndParent.SetRedraw(FALSE);
+
+ HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);
+
+ if(bMaximized)
+ {
+ // Maximize and redraw everything
+ if(hWnd != NULL)
+ MDIMaximize(hWnd);
+ wndParent.SetRedraw(TRUE);
+ wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
+ ::SetFocus(GetMDIFrame()); // focus will be set back to this window
+ }
+ else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
+ {
+ ::SetFocus(hWnd);
+ }
+
+ return hWnd;
+ }
+
+ HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
+ {
+ const int cchName = 256;
+ TCHAR szWindowName[cchName];
+ szWindowName[0] = 0;
+ if(lpcstrWindowName == NULL)
+ {
+ ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
+ lpcstrWindowName = szWindowName;
+ }
+
+ T* pT = static_cast<T*>(this);
+ HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);
+
+ if(hWnd != NULL)
+ m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
+
+ return hWnd;
+ }
+
+ BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
+ {
+ ATLASSERT(!::IsWindow(m_hWndToolBar));
+ if(nResourceID == 0)
+ nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
+ m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
+ return (m_hWndToolBar != NULL);
+ }
+
+ BOOL UpdateClientEdge(LPRECT lpRect = NULL)
+ {
+ // only adjust for active MDI child window
+ HWND hWndChild = MDIGetActive();
+ if(hWndChild != NULL && hWndChild != m_hWnd)
+ return FALSE;
+
+ // need to adjust the client edge style as max/restore happens
+ DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE);
+ DWORD dwNewStyle = dwStyle;
+ if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0))
+ dwNewStyle &= ~(WS_EX_CLIENTEDGE);
+ else
+ dwNewStyle |= WS_EX_CLIENTEDGE;
+
+ if(dwStyle != dwNewStyle)
+ {
+ // SetWindowPos will not move invalid bits
+ ::RedrawWindow(m_hWndMDIClient, NULL, NULL,
+ RDW_INVALIDATE | RDW_ALLCHILDREN);
+ // remove/add WS_EX_CLIENTEDGE to MDI client area
+ ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
+ ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
+ SWP_NOZORDER | SWP_NOCOPYBITS);
+
+ // return new client area
+ if (lpRect != NULL)
+ ::GetClientRect(m_hWndMDIClient, lpRect);
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
+ BEGIN_MSG_MAP(CMDIChildWindowImpl)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
+ MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
+ MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
+ MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
+#endif // (_WIN32_IE >= 0x0400)
+#if (_WIN32_IE >= 0x0500)
+ NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_ATL_NO_REBAR_SUPPORT
+ CHAIN_MSG_MAP(_baseClass)
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ DefWindowProc(uMsg, wParam, lParam); // needed for MDI children
+ if(wParam != SIZE_MINIMIZED)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+ return 0;
+ }
+
+ LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ // update MDI client edge and adjust MDI child rect
+ LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;
+
+ if(!(lpWndPos->flags & SWP_NOSIZE))
+ {
+ RECT rectClient;
+ if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0))
+ {
+ ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle());
+ lpWndPos->x = rectClient.left;
+ lpWndPos->y = rectClient.top;
+ lpWndPos->cx = rectClient.right - rectClient.left;
+ lpWndPos->cy = rectClient.bottom - rectClient.top;
+ }
+ }
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
+
+ // Activate this MDI window if needed
+ if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT)
+ {
+ if(MDIGetActive() != m_hWnd)
+ MDIActivate(m_hWnd);
+ }
+
+ return lRes;
+ }
+
+ LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam);
+ }
+
+ LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if((HWND)lParam == m_hWnd && m_hMenu != NULL)
+ SetMDIFrameMenu();
+ else if((HWND)lParam == NULL)
+ ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_hMenu != NULL)
+ {
+ ::DestroyMenu(m_hMenu);
+ m_hMenu = NULL;
+ }
+ UpdateClientEdge();
+ bHandled = FALSE;
+ return 1;
+ }
+
+#ifndef _ATL_NO_REBAR_SUPPORT
+#if (_WIN32_IE >= 0x0400)
+ LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout(FALSE);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0400)
+
+#if (_WIN32_IE >= 0x0500)
+ LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
+ if(!pT->PrepareChevronMenu(cmi))
+ {
+ bHandled = FALSE;
+ return 1;
+ }
+ // display a popup menu with hidden items
+ pT->DisplayChevronMenu(cmi);
+ // cleanup
+ pT->CleanupChevronMenu(cmi);
+ return 0;
+ }
+#endif // (_WIN32_IE >= 0x0500)
+#endif // !_ATL_NO_REBAR_SUPPORT
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// COwnerDraw - MI class for owner-draw support
+
+template <class T>
+class COwnerDraw
+{
+public:
+#if (_ATL_VER < 0x0700)
+ BOOL m_bHandledOD;
+
+ BOOL IsMsgHandled() const
+ {
+ return m_bHandledOD;
+ }
+ void SetMsgHandled(BOOL bHandled)
+ {
+ m_bHandledOD = bHandled;
+ }
+#endif // (_ATL_VER < 0x0700)
+
+// Message map and handlers
+ BEGIN_MSG_MAP(COwnerDraw< T >)
+ MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
+ MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
+ MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
+ MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
+ ALT_MSG_MAP(1)
+ MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
+ MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
+ MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
+ MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
+ END_MSG_MAP()
+
+ LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetMsgHandled(TRUE);
+ pT->DrawItem((LPDRAWITEMSTRUCT)lParam);
+ bHandled = pT->IsMsgHandled();
+ return (LRESULT)TRUE;
+ }
+
+ LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetMsgHandled(TRUE);
+ pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);
+ bHandled = pT->IsMsgHandled();
+ return (LRESULT)TRUE;
+ }
+
+ LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetMsgHandled(TRUE);
+ bHandled = pT->IsMsgHandled();
+ return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);
+ }
+
+ LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetMsgHandled(TRUE);
+ pT->DeleteItem((LPDELETEITEMSTRUCT)lParam);
+ bHandled = pT->IsMsgHandled();
+ return (LRESULT)TRUE;
+ }
+
+// Overrideables
+ void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
+ {
+ // must be implemented
+ ATLASSERT(FALSE);
+ }
+
+ void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+ {
+ if(lpMeasureItemStruct->CtlType != ODT_MENU)
+ {
+ // return default height for a system font
+ T* pT = static_cast<T*>(this);
+ HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);
+ CClientDC dc(hWnd);
+ TEXTMETRIC tm = { 0 };
+ dc.GetTextMetrics(&tm);
+
+ lpMeasureItemStruct->itemHeight = tm.tmHeight;
+ }
+ else
+ lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);
+ }
+
+ int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)
+ {
+ // all items are equal
+ return 0;
+ }
+
+ void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
+ {
+ // default - nothing
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Update UI macros
+
+// these build the Update UI map inside a class definition
+#define BEGIN_UPDATE_UI_MAP(thisClass) \
+ static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \
+ { \
+ static const _AtlUpdateUIMap theMap[] = \
+ {
+
+#define UPDATE_ELEMENT(nID, wType) \
+ { nID, wType },
+
+#define END_UPDATE_UI_MAP() \
+ { (WORD)-1, 0 } \
+ }; \
+ return theMap; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// CUpdateUI - manages UI elements updating
+
+class CUpdateUIBase
+{
+public:
+ // constants
+ enum
+ {
+ // UI element type
+ UPDUI_MENUPOPUP = 0x0001,
+ UPDUI_MENUBAR = 0x0002,
+ UPDUI_CHILDWINDOW = 0x0004,
+ UPDUI_TOOLBAR = 0x0008,
+ UPDUI_STATUSBAR = 0x0010,
+ // state
+ UPDUI_ENABLED = 0x0000,
+ UPDUI_DISABLED = 0x0100,
+ UPDUI_CHECKED = 0x0200,
+ UPDUI_CHECKED2 = 0x0400,
+ UPDUI_RADIO = 0x0800,
+ UPDUI_DEFAULT = 0x1000,
+ UPDUI_TEXT = 0x2000,
+ // internal state
+ UPDUI_CLEARDEFAULT = 0x4000,
+ };
+
+ // element data
+ struct _AtlUpdateUIElement
+ {
+ HWND m_hWnd;
+ WORD m_wType;
+
+ bool operator ==(const _AtlUpdateUIElement& e) const
+ { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); }
+ };
+
+ // map data
+ struct _AtlUpdateUIMap
+ {
+ WORD m_nID;
+ WORD m_wType;
+
+ bool operator ==(const _AtlUpdateUIMap& e) const
+ { return (m_nID == e.m_nID && m_wType == e.m_wType); }
+ };
+
+ // instance data
+ struct _AtlUpdateUIData
+ {
+ WORD m_wState;
+ union
+ {
+ void* m_lpData;
+ LPTSTR m_lpstrText;
+ struct
+ {
+ WORD m_nIDFirst;
+ WORD m_nIDLast;
+ };
+ };
+
+ bool operator ==(const _AtlUpdateUIData& e) const
+ { return (m_wState == e.m_wState && m_lpData == e.m_lpData); }
+ };
+
+ ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data
+ const _AtlUpdateUIMap* m_pUIMap; // static UI data
+ _AtlUpdateUIData* m_pUIData; // instance UI data
+ WORD m_wDirtyType; // global dirty flag
+
+ bool m_bBlockAccelerators;
+
+
+// Constructor, destructor
+ CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)
+ { }
+
+ ~CUpdateUIBase()
+ {
+ if(m_pUIMap != NULL && m_pUIData != NULL)
+ {
+ const _AtlUpdateUIMap* pUIMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ while(pUIMap->m_nID != (WORD)-1)
+ {
+ if(pUIData->m_wState & UPDUI_TEXT)
+ delete [] pUIData->m_lpstrText;
+ pUIMap++;
+ pUIData++;
+ }
+ delete [] m_pUIData;
+ }
+ }
+
+// Check for disabled commands
+ bool UIGetBlockAccelerators() const
+ {
+ return m_bBlockAccelerators;
+ }
+
+ bool UISetBlockAccelerators(bool bBlock)
+ {
+ bool bOld = m_bBlockAccelerators;
+ m_bBlockAccelerators = bBlock;
+ return bOld;
+ }
+
+// Add elements
+ BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu)
+ {
+ if(hWnd == NULL)
+ return FALSE;
+ _AtlUpdateUIElement e;
+ e.m_hWnd = hWnd;
+ e.m_wType = UPDUI_MENUBAR;
+ return m_UIElements.Add(e);
+ }
+
+ BOOL UIAddToolBar(HWND hWnd) // toolbar
+ {
+ if(hWnd == NULL)
+ return FALSE;
+ _AtlUpdateUIElement e;
+ e.m_hWnd = hWnd;
+ e.m_wType = UPDUI_TOOLBAR;
+ return m_UIElements.Add(e);
+ }
+
+ BOOL UIAddStatusBar(HWND hWnd) // status bar
+ {
+ if(hWnd == NULL)
+ return FALSE;
+ _AtlUpdateUIElement e;
+ e.m_hWnd = hWnd;
+ e.m_wType = UPDUI_STATUSBAR;
+ return m_UIElements.Add(e);
+ }
+
+ BOOL UIAddChildWindowContainer(HWND hWnd) // child window
+ {
+ if(hWnd == NULL)
+ return FALSE;
+ _AtlUpdateUIElement e;
+ e.m_hWnd = hWnd;
+ e.m_wType = UPDUI_CHILDWINDOW;
+ return m_UIElements.Add(e);
+ }
+
+// Message map for popup menu updates and accelerator blocking
+ BEGIN_MSG_MAP(CUpdateUIBase)
+ MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
+ MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+ END_MSG_MAP()
+
+ LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+ HMENU hMenu = (HMENU)wParam;
+ if(hMenu == NULL)
+ return 1;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return 1;
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ while(pMap->m_nID != (WORD)-1)
+ {
+ if(pMap->m_wType & UPDUI_MENUPOPUP)
+ {
+ UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
+
+ if((pUIData->m_wState & UPDUI_RADIO) != 0)
+ ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND);
+ }
+ pMap++;
+ pUIData++;
+ }
+ return 0;
+ }
+
+ LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ bHandled = FALSE;
+ if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only
+ {
+ int nID = LOWORD(wParam);
+ if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID);
+ bHandled = TRUE; // eat the command, UI item is disabled
+ }
+ }
+ return 0;
+ }
+
+// methods for setting UI element state
+ BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ if(bEnable)
+ {
+ if(pUIData->m_wState & UPDUI_DISABLED)
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_DISABLED;
+ }
+ }
+ else
+ {
+ if(!(pUIData->m_wState & UPDUI_DISABLED))
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState |= UPDUI_DISABLED;
+ }
+ }
+
+ if(bForceUpdate)
+ pUIData->m_wState |= pMap->m_wType;
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+
+ break; // found
+ }
+ }
+
+ return TRUE;
+ }
+
+ BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ switch(nCheck)
+ {
+ case 0:
+ if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);
+ }
+ break;
+ case 1:
+ if(!(pUIData->m_wState & UPDUI_CHECKED))
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_CHECKED2;
+ pUIData->m_wState |= UPDUI_CHECKED;
+ }
+ break;
+ case 2:
+ if(!(pUIData->m_wState & UPDUI_CHECKED2))
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_CHECKED;
+ pUIData->m_wState |= UPDUI_CHECKED2;
+ }
+ break;
+ }
+
+ if(bForceUpdate)
+ pUIData->m_wState |= pMap->m_wType;
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+
+ break; // found
+ }
+ }
+
+ return TRUE;
+ }
+
+ // variant that supports bool (checked/not-checked, no intermediate state)
+ BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
+ {
+ return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate);
+ }
+
+ BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ if(bRadio)
+ {
+ if(!(pUIData->m_wState & UPDUI_RADIO))
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState |= UPDUI_RADIO;
+ }
+ }
+ else
+ {
+ if(pUIData->m_wState & UPDUI_RADIO)
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_RADIO;
+ }
+ }
+
+ if(bForceUpdate)
+ pUIData->m_wState |= pMap->m_wType;
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+
+ break; // found
+ }
+ }
+
+ return TRUE;
+ }
+
+ // for menu items
+ BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState |= UPDUI_RADIO;
+ pUIData->m_nIDFirst = (WORD)nIDFirst;
+ pUIData->m_nIDLast = (WORD)nIDLast;
+
+ if(bForceUpdate)
+ pUIData->m_wState |= pMap->m_wType;
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+ }
+ else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast)
+ {
+ if(pUIData->m_wState & UPDUI_RADIO)
+ {
+ pUIData->m_wState &= ~pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_RADIO;
+ pUIData->m_nIDFirst = 0;
+ pUIData->m_nIDLast = 0;
+ }
+ }
+
+ if(pMap->m_nID == nIDLast)
+ break;
+ }
+
+ return TRUE;
+ }
+
+ BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+ if(lpstrText == NULL)
+ lpstrText = _T("");
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText))
+ {
+ delete [] pUIData->m_lpstrText;
+ pUIData->m_lpstrText = NULL;
+ int nStrLen = lstrlen(lpstrText);
+ ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]);
+ if(pUIData->m_lpstrText == NULL)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n"));
+ break;
+ }
+ SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText);
+ pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
+ }
+
+ if(bForceUpdate)
+ pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+
+ break; // found
+ }
+ }
+
+ return TRUE;
+ }
+
+ BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ if(bDefault)
+ {
+ if((pUIData->m_wState & UPDUI_DEFAULT) == 0)
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState |= UPDUI_DEFAULT;
+ }
+ }
+ else
+ {
+ if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
+ {
+ pUIData->m_wState |= pMap->m_wType;
+ pUIData->m_wState &= ~UPDUI_DEFAULT;
+ pUIData->m_wState |= UPDUI_CLEARDEFAULT;
+ }
+ }
+
+ if(bForceUpdate)
+ pUIData->m_wState |= pMap->m_wType;
+ if(pUIData->m_wState & pMap->m_wType)
+ m_wDirtyType |= pMap->m_wType;
+
+ break; // found
+ }
+ }
+
+ return TRUE;
+ }
+
+// methods for complete state set/get
+ BOOL UISetState(int nID, DWORD dwState)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ {
+ pUIData->m_wState = (WORD)(dwState | pMap->m_wType);
+ m_wDirtyType |= pMap->m_wType;
+ break; // found
+ }
+ }
+ return TRUE;
+ }
+
+ DWORD UIGetState(int nID)
+ {
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return 0;
+ for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
+ {
+ if(nID == (int)pMap->m_nID)
+ return pUIData->m_wState;
+ }
+ return 0;
+ }
+
+// methods for updating UI
+#ifndef _WIN32_WCE
+ BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)
+ {
+ if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)
+ return TRUE;
+
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ while(pMap->m_nID != (WORD)-1)
+ {
+ for(int i = 0; i < m_UIElements.GetSize(); i++)
+ {
+ if(m_UIElements[i].m_wType == UPDUI_MENUBAR)
+ {
+ HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);
+ if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))
+ UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
+ }
+ if(bMainMenu)
+ ::DrawMenuBar(m_UIElements[i].m_hWnd);
+ }
+ pMap++;
+ pUIData->m_wState &= ~UPDUI_MENUBAR;
+ if(pUIData->m_wState & UPDUI_TEXT)
+ {
+ delete [] pUIData->m_lpstrText;
+ pUIData->m_lpstrText = NULL;
+ pUIData->m_wState &= ~UPDUI_TEXT;
+ }
+ pUIData++;
+ }
+
+ m_wDirtyType &= ~UPDUI_MENUBAR;
+ return TRUE;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)
+ {
+ if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)
+ return TRUE;
+
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ while(pMap->m_nID != (WORD)-1)
+ {
+ for(int i = 0; i < m_UIElements.GetSize(); i++)
+ {
+ if(m_UIElements[i].m_wType == UPDUI_TOOLBAR)
+ {
+ if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))
+ UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
+ }
+ }
+ pMap++;
+ pUIData->m_wState &= ~UPDUI_TOOLBAR;
+ pUIData++;
+ }
+
+ m_wDirtyType &= ~UPDUI_TOOLBAR;
+ return TRUE;
+ }
+
+ BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
+ {
+ if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
+ return TRUE;
+
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ while(pMap->m_nID != (WORD)-1)
+ {
+ for(int i = 0; i < m_UIElements.GetSize(); i++)
+ {
+ if(m_UIElements[i].m_wType == UPDUI_STATUSBAR)
+ {
+ if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))
+ UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
+ }
+ }
+ pMap++;
+ pUIData->m_wState &= ~UPDUI_STATUSBAR;
+ if(pUIData->m_wState & UPDUI_TEXT)
+ {
+ delete [] pUIData->m_lpstrText;
+ pUIData->m_lpstrText = NULL;
+ pUIData->m_wState &= ~UPDUI_TEXT;
+ }
+ pUIData++;
+ }
+
+ m_wDirtyType &= ~UPDUI_STATUSBAR;
+ return TRUE;
+ }
+
+ BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
+ {
+ if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
+ return TRUE;
+
+ const _AtlUpdateUIMap* pMap = m_pUIMap;
+ _AtlUpdateUIData* pUIData = m_pUIData;
+ if(pUIData == NULL)
+ return FALSE;
+
+ while(pMap->m_nID != (WORD)-1)
+ {
+ for(int i = 0; i < m_UIElements.GetSize(); i++)
+ {
+ if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
+ {
+ if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
+ UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
+ }
+ }
+ pMap++;
+ pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
+ if(pUIData->m_wState & UPDUI_TEXT)
+ {
+ delete [] pUIData->m_lpstrText;
+ pUIData->m_lpstrText = NULL;
+ pUIData->m_wState &= ~UPDUI_TEXT;
+ }
+ pUIData++;
+ }
+
+ m_wDirtyType &= ~UPDUI_CHILDWINDOW;
+ return TRUE;
+ }
+
+// internal element specific methods
+ static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)
+ {
+#ifndef _WIN32_WCE
+ if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0)
+ {
+ ::SetMenuDefaultItem(hMenu, (UINT)-1, 0);
+ pUIData->m_wState &= ~UPDUI_CLEARDEFAULT;
+ }
+#endif // !_WIN32_WCE
+
+ CMenuItemInfo mii;
+ mii.fMask = MIIM_STATE;
+ mii.wID = nID;
+
+#ifndef _WIN32_WCE
+ if((pUIData->m_wState & UPDUI_DISABLED) != 0)
+ mii.fState |= MFS_DISABLED | MFS_GRAYED;
+ else
+ mii.fState |= MFS_ENABLED;
+
+ if((pUIData->m_wState & UPDUI_CHECKED) != 0)
+ mii.fState |= MFS_CHECKED;
+ else
+ mii.fState |= MFS_UNCHECKED;
+
+ if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
+ mii.fState |= MFS_DEFAULT;
+#else // CE specific
+ // ::SetMenuItemInfo() can't disable or check menu items
+ // on Windows CE, so we have to do that directly
+ UINT uEnable = MF_BYCOMMAND;
+ if((pUIData->m_wState & UPDUI_DISABLED) != 0)
+ uEnable |= MF_GRAYED;
+ else
+ uEnable |= MF_ENABLED;
+ ::EnableMenuItem(hMenu, nID, uEnable);
+
+ UINT uCheck = MF_BYCOMMAND;
+ if((pUIData->m_wState & UPDUI_CHECKED) != 0)
+ uCheck |= MF_CHECKED;
+ else
+ uCheck |= MF_UNCHECKED;
+ ::CheckMenuItem(hMenu, nID, uCheck);
+#endif // _WIN32_WCE
+
+ if((pUIData->m_wState & UPDUI_TEXT) != 0)
+ {
+ CMenuItemInfo miiNow;
+ miiNow.fMask = MIIM_TYPE;
+ miiNow.wID = nID;
+ if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow))
+ {
+ mii.fMask |= MIIM_TYPE;
+ // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING
+#ifndef _WIN32_WCE
+ mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING;
+#else // CE specific
+ mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING;
+#endif // _WIN32_WCE
+ mii.dwTypeData = pUIData->m_lpstrText;
+ }
+ }
+
+ ::SetMenuItemInfo(hMenu, nID, FALSE, &mii);
+ }
+
+ static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)
+ {
+ // Note: only handles enabled/disabled, checked state, and radio (press)
+ ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
+ ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);
+ ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);
+ ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);
+ }
+
+ static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)
+ {
+ // Note: only handles text
+ if(pUIData->m_wState & UPDUI_TEXT)
+ ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText);
+ }
+
+ static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)
+ {
+ HWND hChild = ::GetDlgItem(hWnd, nID);
+
+ ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
+ // for check and radio, assume that window is a button
+ int nCheck = BST_UNCHECKED;
+ if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO)
+ nCheck = BST_CHECKED;
+ else if(pUIData->m_wState & UPDUI_CHECKED2)
+ nCheck = BST_INDETERMINATE;
+ ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);
+ if(pUIData->m_wState & UPDUI_DEFAULT)
+ {
+ DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);
+ if(HIWORD(dwRet) == DC_HASDEFID)
+ {
+ HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));
+ // remove BS_DEFPUSHBUTTON
+ ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
+ }
+ ::SendMessage(hWnd, DM_SETDEFID, nID, 0L);
+ }
+ if(pUIData->m_wState & UPDUI_TEXT)
+ ::SetWindowText(hChild, pUIData->m_lpstrText);
+ }
+};
+
+template <class T>
+class CUpdateUI : public CUpdateUIBase
+{
+public:
+ CUpdateUI()
+ {
+ T* pT = static_cast<T*>(this);
+ pT;
+ const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
+ m_pUIMap = pMap;
+ ATLASSERT(m_pUIMap != NULL);
+ int nCount;
+ for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++)
+ pMap++;
+
+ // check for duplicates (debug only)
+#ifdef _DEBUG
+ for(int i = 0; i < nCount; i++)
+ {
+ for(int j = 0; j < nCount; j++)
+ {
+ // shouldn't have duplicates in the update UI map
+ if(i != j)
+ ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);
+ }
+ }
+#endif // _DEBUG
+
+ ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);
+ ATLASSERT(m_pUIData != NULL);
+
+ if(m_pUIData != NULL)
+ memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDynamicUpdateUI - allows update elements to dynamically added and removed
+// in addition to a static update UI map
+
+template <class T>
+class CDynamicUpdateUI : public CUpdateUIBase
+{
+public:
+// Data members
+ ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data
+ ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data
+
+// Constructor/destructor
+ CDynamicUpdateUI()
+ {
+ T* pT = static_cast<T*>(this);
+ pT;
+ const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
+ ATLASSERT(pMap != NULL);
+
+ for(;;)
+ {
+ BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap);
+ ATLASSERT(bRet);
+
+ if(bRet != FALSE)
+ {
+ _AtlUpdateUIData data = { 0, NULL };
+ bRet = m_arrUIData.Add(data);
+ ATLASSERT(bRet);
+ }
+
+ if(pMap->m_nID == (WORD)-1)
+ break;
+
+ pMap++;
+ }
+
+ ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize());
+
+#ifdef _DEBUG
+ // check for duplicates (debug only)
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ for(int j = 0; j < m_arrUIMap.GetSize(); j++)
+ {
+ // shouldn't have duplicates in the update UI map
+ if(i != j)
+ ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID);
+ }
+ }
+#endif // _DEBUG
+
+ // Set internal data pointers to point to the new data arrays
+ m_pUIMap = m_arrUIMap.m_aT;
+ m_pUIData = m_arrUIData.m_aT;
+ }
+
+ ~CDynamicUpdateUI()
+ {
+ for(int i = 0; i < m_arrUIData.GetSize(); i++)
+ {
+ if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)
+ delete [] m_arrUIData[i].m_lpstrText;
+ }
+
+ // Reset internal data pointers (memory will be released by CSimpleArray d-tor)
+ m_pUIMap = NULL;
+ m_pUIData = NULL;
+ }
+
+// Methods for dynamically adding and removing update elements
+ bool UIAddUpdateElement(WORD nID, WORD wType)
+ {
+ // check for duplicates
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ // shouldn't have duplicates in the update UI map
+ ATLASSERT(m_arrUIMap[i].m_nID != nID);
+ if(m_arrUIMap[i].m_nID == nID)
+ return false;
+ }
+
+ bool bRetVal = false;
+
+ // Add new end element
+ _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 };
+ BOOL bRet = m_arrUIMap.Add(uumEnd);
+ ATLASSERT(bRet);
+
+ if(bRet != FALSE)
+ {
+ _AtlUpdateUIData uud = { 0, NULL };
+ bRet = m_arrUIData.Add(uud);
+ ATLASSERT(bRet);
+
+ // Set new data to the previous end element
+ if(bRet != FALSE)
+ {
+ int nSize = m_arrUIMap.GetSize();
+ _AtlUpdateUIMap uum = { nID, wType };
+ m_arrUIMap.SetAtIndex(nSize - 2, uum);
+ m_arrUIData.SetAtIndex(nSize - 2, uud);
+
+ // Set internal data pointers again, just in case that memory moved
+ m_pUIMap = m_arrUIMap.m_aT;
+ m_pUIData = m_arrUIData.m_aT;
+
+ bRetVal = true;
+ }
+ }
+
+ return bRetVal;
+ }
+
+ bool UIRemoveUpdateElement(WORD nID)
+ {
+ bool bRetVal = false;
+
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ if(m_arrUIMap[i].m_nID == nID)
+ {
+ BOOL bRet = m_arrUIMap.RemoveAt(i);
+ ATLASSERT(bRet);
+ bRet = m_arrUIData.RemoveAt(i);
+ ATLASSERT(bRet);
+
+ bRetVal = true;
+ break;
+ }
+ }
+
+ return bRetVal;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAutoUpdateUI : Automatic mapping of UI elements
+
+template <class T>
+class CAutoUpdateUI : public CDynamicUpdateUI<T>
+{
+public:
+ LPCTSTR UIGetText(int nID)
+ {
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ if(m_arrUIMap[i].m_nID == nID)
+ return m_arrUIData[i].m_lpstrText;
+ }
+
+ return NULL;
+ }
+
+// Element
+ template <WORD t_wType>
+ bool UIAddElement(UINT nID)
+ {
+ // check for existing UI map element
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ if(m_arrUIMap[i].m_nID == nID)
+ {
+ // set requested type
+ m_arrUIMap[i].m_wType |= t_wType;
+ return true;
+ }
+ }
+
+ // Add element to UI map with requested type
+ return UIAddUpdateElement((WORD)nID, t_wType);
+ }
+
+ template <WORD t_wType>
+ bool UIRemoveElement(UINT nID)
+ {
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ if(m_arrUIMap[i].m_nID == nID) // matching UI map element
+ {
+ WORD wType = m_arrUIMap[i].m_wType & ~t_wType;
+ if (wType) // has other types
+ {
+ m_arrUIMap[i].m_wType = wType; // keep other types
+ return true;
+ }
+ else
+ {
+ return UIRemoveUpdateElement((WORD)nID);
+ }
+ }
+ }
+
+ return false;
+ }
+
+// Menu
+ bool UIAddMenu(HMENU hMenu, bool bSetText = false)
+ {
+#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
+ using ATL::GetMenuString;
+#endif
+ ATLASSERT(::IsMenu(hMenu));
+ MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU};
+
+ // Complete the UI map
+ for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++)
+ {
+ if(mii.hSubMenu)
+ {
+ // Add submenu to UI map
+ UIAddMenu(mii.hSubMenu, bSetText);
+ }
+ else if (mii.wID)
+ {
+ // Add element to UI map
+ UIAddElement<UPDUI_MENUPOPUP>(mii.wID);
+#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+ if (bSetText)
+ {
+ TCHAR sText[64] = { 0 };
+ if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION))
+ UISetText(mii.wID, sText);
+ }
+#else
+ bSetText;
+#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+ }
+ }
+
+ return true;
+ }
+
+ bool UIAddMenu(UINT uID, bool bSetText = false)
+ {
+ CMenu menu;
+ ATLVERIFY(menu.LoadMenu(uID));
+ return UIAddMenu(menu, bSetText);
+ }
+
+// ToolBar
+#ifndef BTNS_SEP
+ #define BTNS_SEP TBSTYLE_SEP
+#endif // BTNS_SEP compatibility
+
+#if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))
+ bool UIAddToolBar(HWND hWndToolBar)
+ {
+ ATLASSERT(::IsWindow(hWndToolBar));
+ TBBUTTONINFO tbbi = {sizeof TBBUTTONINFO, TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX};
+
+ // Add toolbar buttons
+ for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++)
+ {
+ if (tbbi.fsStyle ^ BTNS_SEP)
+ UIAddElement<UPDUI_TOOLBAR>(tbbi.idCommand);
+ }
+
+ // Add embedded controls if any
+ if (::GetWindow(hWndToolBar, GW_CHILD))
+ UIAddChildWindowContainer(hWndToolBar);
+
+ return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE);
+ }
+#endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))
+
+// Container
+ bool UIAddChildWindowContainer(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(hWnd));
+
+ // Add children controls if any
+ for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT))
+ {
+ if (int id = wCtl.GetDlgCtrlID())
+ UIAddElement<UPDUI_CHILDWINDOW>(id);
+ }
+
+ return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE);
+ }
+
+// StatusBar
+ BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
+ {
+ if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
+ return TRUE;
+
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ for(int e = 0; e < m_UIElements.GetSize(); e++)
+ {
+ if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) &&
+ (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) &&
+ (m_arrUIData[i].m_wState & UPDUI_STATUSBAR))
+ {
+ UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd);
+ m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR;
+ if(m_arrUIData[i].m_wState & UPDUI_TEXT)
+ m_arrUIData[i].m_wState &= ~UPDUI_TEXT;
+ }
+ }
+ }
+
+ m_wDirtyType &= ~UPDUI_STATUSBAR;
+ return TRUE;
+ }
+
+ bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1)
+ {
+ ATLASSERT(::IsWindow(hWndStatusBar));
+
+ // Add StatusBar panes
+ for (int iPane = 0; iPane < nPanes; iPane++)
+ UIAddElement<UPDUI_STATUSBAR>(ID_DEFAULT_PANE + iPane);
+
+ return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE);
+ }
+
+// UI Map used if derived class has none
+ BEGIN_UPDATE_UI_MAP(CAutoUpdateUI)
+ END_UPDATE_UI_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDialogResize - provides support for resizing dialog controls
+// (works for any window that has child controls)
+
+// Put CDialogResize in the list of base classes for a dialog (or even plain window),
+// then implement DLGRESIZE map by specifying controls and groups of control
+// and using DLSZ_* values to specify how are they supposed to be resized.
+//
+// Notes:
+// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template
+// for top level dialogs (popup or overlapped), so that users can resize the dialog.
+// - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X,
+// DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined.
+// - Order of controls is important - group controls are resized and moved based
+// on the position of the previous control in a group.
+
+// dialog resize map macros
+#define BEGIN_DLGRESIZE_MAP(thisClass) \
+ static const _AtlDlgResizeMap* GetDlgResizeMap() \
+ { \
+ static const _AtlDlgResizeMap theMap[] = \
+ {
+
+#define END_DLGRESIZE_MAP() \
+ { -1, 0 }, \
+ }; \
+ return theMap; \
+ }
+
+#define DLGRESIZE_CONTROL(id, flags) \
+ { id, flags },
+
+#define BEGIN_DLGRESIZE_GROUP() \
+ { -1, _DLSZ_BEGIN_GROUP },
+
+#define END_DLGRESIZE_GROUP() \
+ { -1, _DLSZ_END_GROUP },
+
+
+template <class T>
+class CDialogResize
+{
+public:
+// Data declarations and members
+ enum
+ {
+ DLSZ_SIZE_X = 0x00000001,
+ DLSZ_SIZE_Y = 0x00000002,
+ DLSZ_MOVE_X = 0x00000004,
+ DLSZ_MOVE_Y = 0x00000008,
+ DLSZ_REPAINT = 0x00000010,
+ DLSZ_CENTER_X = 0x00000020,
+ DLSZ_CENTER_Y = 0x00000040,
+
+ // internal use only
+ _DLSZ_BEGIN_GROUP = 0x00001000,
+ _DLSZ_END_GROUP = 0x00002000,
+ _DLSZ_GRIPPER = 0x00004000
+ };
+
+ struct _AtlDlgResizeMap
+ {
+ int m_nCtlID;
+ DWORD m_dwResizeFlags;
+ };
+
+ struct _AtlDlgResizeData
+ {
+ int m_nCtlID;
+ DWORD m_dwResizeFlags;
+ RECT m_rect;
+
+ int GetGroupCount() const
+ {
+ return (int)LOBYTE(HIWORD(m_dwResizeFlags));
+ }
+
+ void SetGroupCount(int nCount)
+ {
+ ATLASSERT(nCount > 0 && nCount < 256);
+ DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));
+ m_dwResizeFlags &= 0xFF00FFFF;
+ m_dwResizeFlags |= dwCount;
+ }
+
+ bool operator ==(const _AtlDlgResizeData& r) const
+ { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); }
+ };
+
+ ATL::CSimpleArray<_AtlDlgResizeData> m_arrData;
+ SIZE m_sizeDialog;
+ POINT m_ptMinTrackSize;
+ bool m_bGripper;
+
+
+// Constructor
+ CDialogResize() : m_bGripper(false)
+ {
+ m_sizeDialog.cx = 0;
+ m_sizeDialog.cy = 0;
+ m_ptMinTrackSize.x = -1;
+ m_ptMinTrackSize.y = -1;
+ }
+
+// Operations
+ void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ DWORD dwStyle = pT->GetStyle();
+
+#ifdef _DEBUG
+ // Debug only: Check if top level dialogs have a resizeable border.
+ if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0))
+ ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n"));
+#endif // _DEBUG
+
+ // Force specified styles (default WS_CLIPCHILDREN reduces flicker)
+ if((dwStyle & dwForceStyle) != dwForceStyle)
+ pT->ModifyStyle(0, dwForceStyle);
+
+ // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have.
+ // Setting icon to NULL is required when XP themes are active.
+ // Note: This will not prevent adding an icon for the dialog using SetIcon()
+ if((dwStyle & WS_CHILD) == 0)
+ {
+ pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME);
+ if(pT->GetIcon(FALSE) == NULL)
+ pT->SetIcon(NULL, FALSE);
+ }
+
+ // Cleanup in case of multiple initialization
+ // block: first check for the gripper control, destroy it if needed
+ {
+ ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
+ if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)
+ wndGripper.DestroyWindow();
+ }
+ // clear out everything else
+ m_arrData.RemoveAll();
+ m_sizeDialog.cx = 0;
+ m_sizeDialog.cy = 0;
+ m_ptMinTrackSize.x = -1;
+ m_ptMinTrackSize.y = -1;
+
+ // Get initial dialog client size
+ RECT rectDlg = { 0 };
+ pT->GetClientRect(&rectDlg);
+ m_sizeDialog.cx = rectDlg.right;
+ m_sizeDialog.cy = rectDlg.bottom;
+
+#ifndef _WIN32_WCE
+ // Create gripper if requested
+ m_bGripper = false;
+ if(bAddGripper)
+ {
+ // shouldn't exist already
+ ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)));
+ if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)))
+ {
+ ATL::CWindow wndGripper;
+ wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR);
+ ATLASSERT(wndGripper.IsWindow());
+ if(wndGripper.IsWindow())
+ {
+ m_bGripper = true;
+ RECT rectCtl = { 0 };
+ wndGripper.GetWindowRect(&rectCtl);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
+ _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
+ m_arrData.Add(data);
+ }
+ }
+ }
+#else // CE specific
+ bAddGripper; // avoid level 4 warning
+#endif // _WIN32_WCE
+
+ // Get min track position if requested
+ if(bUseMinTrackSize)
+ {
+ if((dwStyle & WS_CHILD) != 0)
+ {
+ RECT rect = { 0 };
+ pT->GetClientRect(&rect);
+ m_ptMinTrackSize.x = rect.right - rect.left;
+ m_ptMinTrackSize.y = rect.bottom - rect.top;
+ }
+ else
+ {
+ RECT rect = { 0 };
+ pT->GetWindowRect(&rect);
+ m_ptMinTrackSize.x = rect.right - rect.left;
+ m_ptMinTrackSize.y = rect.bottom - rect.top;
+ }
+ }
+
+ // Walk the map and initialize data
+ const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();
+ ATLASSERT(pMap != NULL);
+ int nGroupStart = -1;
+ for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)
+ {
+ if(pMap->m_nCtlID == -1)
+ {
+ switch(pMap->m_dwResizeFlags)
+ {
+ case _DLSZ_BEGIN_GROUP:
+ ATLASSERT(nGroupStart == -1);
+ nGroupStart = m_arrData.GetSize();
+ break;
+ case _DLSZ_END_GROUP:
+ {
+ ATLASSERT(nGroupStart != -1);
+ int nGroupCount = m_arrData.GetSize() - nGroupStart;
+ m_arrData[nGroupStart].SetGroupCount(nGroupCount);
+ nGroupStart = -1;
+ }
+ break;
+ default:
+ ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
+ break;
+ }
+ }
+ else
+ {
+ // this ID conflicts with the default gripper one
+ ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);
+
+ ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);
+ ATLASSERT(ctl.IsWindow());
+ RECT rectCtl = { 0 };
+ ctl.GetWindowRect(&rectCtl);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
+
+ DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;
+ _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
+ m_arrData.Add(data);
+ }
+ }
+ ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
+ }
+
+ void DlgResize_UpdateLayout(int cxWidth, int cyHeight)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ // Restrict minimum size if requested
+ if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
+ {
+ if(cxWidth < m_ptMinTrackSize.x)
+ cxWidth = m_ptMinTrackSize.x;
+ if(cyHeight < m_ptMinTrackSize.y)
+ cyHeight = m_ptMinTrackSize.y;
+ }
+
+ BOOL bVisible = pT->IsWindowVisible();
+ if(bVisible)
+ pT->SetRedraw(FALSE);
+
+ for(int i = 0; i < m_arrData.GetSize(); i++)
+ {
+ if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group
+ {
+ int nGroupCount = m_arrData[i].GetGroupCount();
+ ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());
+ RECT rectGroup = m_arrData[i].m_rect;
+
+ int j = 1;
+ for(j = 1; j < nGroupCount; j++)
+ {
+ rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left);
+ rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top);
+ rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right);
+ rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
+ }
+
+ for(j = 0; j < nGroupCount; j++)
+ {
+ _AtlDlgResizeData* pDataPrev = NULL;
+ if(j > 0)
+ pDataPrev = &(m_arrData[i + j - 1]);
+ pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev);
+ }
+
+ i += nGroupCount - 1; // increment to skip all group controls
+ }
+ else // one control entry
+ {
+ RECT rectGroup = { 0, 0, 0, 0 };
+ pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
+ }
+ }
+
+ if(bVisible)
+ pT->SetRedraw(TRUE);
+
+ pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CDialogResize)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
+#endif // _WIN32_WCE
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+#ifndef _WIN32_WCE
+ if(m_bGripper)
+ {
+ ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
+ if(wParam == SIZE_MAXIMIZED)
+ wndGripper.ShowWindow(SW_HIDE);
+ else if(wParam == SIZE_RESTORED)
+ wndGripper.ShowWindow(SW_SHOW);
+ }
+#endif // _WIN32_WCE
+ if(wParam != SIZE_MINIMIZED)
+ {
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ }
+ return 0;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
+ {
+ LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
+ lpMMI->ptMinTrackSize = m_ptMinTrackSize;
+ }
+ return 0;
+ }
+#endif // _WIN32_WCE
+
+// Implementation
+ bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup,
+ _AtlDlgResizeData* pDataPrev = NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ ATL::CWindow ctl;
+ RECT rectCtl = { 0 };
+
+ ctl = pT->GetDlgItem(data.m_nCtlID);
+ if(!ctl.GetWindowRect(&rectCtl))
+ return false;
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
+
+ if(bGroup)
+ {
+ if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
+ {
+ int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx;
+ int cxCtl = data.m_rect.right - data.m_rect.left;
+ rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2;
+ rectCtl.right = rectCtl.left + cxCtl;
+ }
+ else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
+ {
+ rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
+
+ if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
+ {
+ rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
+
+ if(pDataPrev != NULL)
+ {
+ ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
+ RECT rcPrev = { 0 };
+ ctlPrev.GetWindowRect(&rcPrev);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
+ int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right);
+ rcPrev.right += dxAdjust;
+ ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
+ }
+ }
+ else
+ {
+ rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
+ }
+ }
+
+ if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
+ {
+ int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy;
+ int cyCtl = data.m_rect.bottom - data.m_rect.top;
+ rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2;
+ rectCtl.bottom = rectCtl.top + cyCtl;
+ }
+ else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
+ {
+ rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
+
+ if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
+ {
+ rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
+
+ if(pDataPrev != NULL)
+ {
+ ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
+ RECT rcPrev = { 0 };
+ ctlPrev.GetWindowRect(&rcPrev);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
+ int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom);
+ rcPrev.bottom += dxAdjust;
+ ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
+ }
+ }
+ else
+ {
+ rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
+ }
+ }
+ }
+ else // no group
+ {
+ if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
+ {
+ int cxCtl = data.m_rect.right - data.m_rect.left;
+ rectCtl.left = (cxWidth - cxCtl) / 2;
+ rectCtl.right = rectCtl.left + cxCtl;
+ }
+ else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
+ {
+ rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
+
+ if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
+ rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
+ }
+
+ if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
+ {
+ int cyCtl = data.m_rect.bottom - data.m_rect.top;
+ rectCtl.top = (cyHeight - cyCtl) / 2;
+ rectCtl.bottom = rectCtl.top + cyCtl;
+ }
+ else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
+ {
+ rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
+
+ if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
+ rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
+ }
+ }
+
+ if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
+ ctl.Invalidate();
+
+ if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0)
+ ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);
+
+ return true;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDoubleBufferImpl - Provides double-buffer painting support to any window
+
+template <class T>
+class CDoubleBufferImpl
+{
+public:
+// Overrideables
+ void DoPaint(CDCHandle /*dc*/)
+ {
+ // must be implemented in a derived class
+ ATLASSERT(FALSE);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CDoubleBufferImpl)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+#endif // !_WIN32_WCE
+ END_MSG_MAP()
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background painting needed
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ if(wParam != NULL)
+ {
+ RECT rect = { 0 };
+ pT->GetClientRect(&rect);
+ CMemoryDC dcMem((HDC)wParam, rect);
+ pT->DoPaint(dcMem.m_hDC);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);
+ pT->DoPaint(dcMem.m_hDC);
+ }
+
+ return 0;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDoubleBufferWindowImpl - Implements a double-buffer painting window
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T >
+{
+public:
+ BEGIN_MSG_MAP(CDoubleBufferWindowImpl)
+ CHAIN_MSG_MAP(CDoubleBufferImpl< T >)
+ END_MSG_MAP()
+};
+
+
+// command bar support
+#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
+ #undef CBRM_GETMENU
+ #undef CBRM_TRACKPOPUPMENU
+ #undef CBRM_GETCMDBAR
+ #undef CBRPOPUPMENU
+#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
+
+}; // namespace WTL
+
+#endif // __ATLFRAME_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLGDI_H__
+#define __ATLGDI_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlgdi.h requires atlapp.h to be included first
+#endif
+
+
+// protect template members from windowsx.h macros
+#ifdef _INC_WINDOWSX
+ #undef CopyRgn
+ #undef CreateBrush
+ #undef CreatePen
+ #undef SelectBrush
+ #undef SelectPen
+ #undef SelectFont
+ #undef SelectBitmap
+#endif // _INC_WINDOWSX
+
+// required libraries
+#if !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE)
+ #pragma comment(lib, "msimg32.lib")
+#endif // !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE)
+#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)
+ #pragma comment(lib, "opengl32.lib")
+#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CPenT<t_bManaged>
+// CBrushT<t_bManaged>
+// CLogFont
+// CFontT<t_bManaged>
+// CBitmapT<t_bManaged>
+// CPaletteT<t_bManaged>
+// CRgnT<t_bManaged>
+// CDCT<t_bManaged>
+// CPaintDC
+// CClientDC
+// CWindowDC
+// CMemoryDC
+// CEnhMetaFileInfo
+// CEnhMetaFileT<t_bManaged>
+// CEnhMetaFileDC
+//
+// Global functions:
+// AtlGetBitmapResourceInfo()
+// AtlGetBitmapResourceBitsPerPixel()
+// AtlIsAlphaBitmapResource()
+// AtlIsDib16()
+// AtlGetDibColorTableSize()
+// AtlGetDibNumColors(),
+// AtlGetDibBitmap()
+// AtlCopyBitmap()
+// AtlCreatePackedDib16()
+// AtlSetClipboardDib16()
+// AtlGetClipboardDib()
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// Bitmap resource helpers to extract bitmap information for a bitmap resource
+
+inline LPBITMAPINFOHEADER AtlGetBitmapResourceInfo(HMODULE hModule, ATL::_U_STRINGorID image)
+{
+ HRSRC hResource = ::FindResource(hModule, image.m_lpstr, RT_BITMAP);
+ ATLASSERT(hResource != NULL);
+ HGLOBAL hGlobal = ::LoadResource(hModule, hResource);
+ ATLASSERT(hGlobal != NULL);
+ LPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal);
+ ATLASSERT(pBitmapInfoHeader != NULL);
+ return pBitmapInfoHeader;
+}
+
+inline WORD AtlGetBitmapResourceBitsPerPixel(HMODULE hModule, ATL::_U_STRINGorID image)
+{
+ LPBITMAPINFOHEADER pBitmapInfoHeader = AtlGetBitmapResourceInfo(hModule, image);
+ ATLASSERT(pBitmapInfoHeader != NULL);
+ return pBitmapInfoHeader->biBitCount;
+}
+
+inline WORD AtlGetBitmapResourceBitsPerPixel(ATL::_U_STRINGorID image)
+{
+ return AtlGetBitmapResourceBitsPerPixel(ModuleHelper::GetResourceInstance(), image);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// 32-bit (alpha channel) bitmap resource helper
+
+// Note: 32-bit (alpha channel) images work only on Windows XP with Common Controls version 6.
+// If you want your app to work on older version of Windows, load non-alpha images if Common
+// Controls version is less than 6.
+
+inline bool AtlIsAlphaBitmapResource(ATL::_U_STRINGorID image)
+{
+ return (AtlGetBitmapResourceBitsPerPixel(image) == 32);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPen
+
+template <bool t_bManaged>
+class CPenT
+{
+public:
+// Data members
+ HPEN m_hPen;
+
+// Constructor/destructor/operators
+ CPenT(HPEN hPen = NULL) : m_hPen(hPen)
+ { }
+
+ ~CPenT()
+ {
+ if(t_bManaged && m_hPen != NULL)
+ DeleteObject();
+ }
+
+ CPenT<t_bManaged>& operator =(HPEN hPen)
+ {
+ Attach(hPen);
+ return *this;
+ }
+
+ void Attach(HPEN hPen)
+ {
+ if(t_bManaged && m_hPen != NULL && m_hPen != hPen)
+ ::DeleteObject(m_hPen);
+ m_hPen = hPen;
+ }
+
+ HPEN Detach()
+ {
+ HPEN hPen = m_hPen;
+ m_hPen = NULL;
+ return hPen;
+ }
+
+ operator HPEN() const { return m_hPen; }
+
+ bool IsNull() const { return (m_hPen == NULL); }
+
+// Create methods
+ HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
+ {
+ ATLASSERT(m_hPen == NULL);
+ m_hPen = ::CreatePen(nPenStyle, nWidth, crColor);
+ return m_hPen;
+ }
+
+#ifndef _WIN32_WCE
+ HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL)
+ {
+ ATLASSERT(m_hPen == NULL);
+ m_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle);
+ return m_hPen;
+ }
+#endif // !_WIN32_WCE
+
+ HPEN CreatePenIndirect(LPLOGPEN lpLogPen)
+ {
+ ATLASSERT(m_hPen == NULL);
+ m_hPen = ::CreatePenIndirect(lpLogPen);
+ return m_hPen;
+ }
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hPen != NULL);
+ BOOL bRet = ::DeleteObject(m_hPen);
+ if(bRet)
+ m_hPen = NULL;
+ return bRet;
+ }
+
+// Attributes
+ int GetLogPen(LOGPEN* pLogPen) const
+ {
+ ATLASSERT(m_hPen != NULL);
+ return ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen);
+ }
+
+ bool GetLogPen(LOGPEN& LogPen) const
+ {
+ ATLASSERT(m_hPen != NULL);
+ return (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN));
+ }
+
+#ifndef _WIN32_WCE
+ int GetExtLogPen(EXTLOGPEN* pLogPen) const
+ {
+ ATLASSERT(m_hPen != NULL);
+ return ::GetObject(m_hPen, sizeof(EXTLOGPEN), pLogPen);
+ }
+
+ bool GetExtLogPen(EXTLOGPEN& ExtLogPen) const
+ {
+ ATLASSERT(m_hPen != NULL);
+ return (::GetObject(m_hPen, sizeof(EXTLOGPEN), &ExtLogPen) == sizeof(EXTLOGPEN));
+ }
+#endif // !_WIN32_WCE
+};
+
+typedef CPenT<false> CPenHandle;
+typedef CPenT<true> CPen;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBrush
+
+template <bool t_bManaged>
+class CBrushT
+{
+public:
+// Data members
+ HBRUSH m_hBrush;
+
+// Constructor/destructor/operators
+ CBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush)
+ { }
+
+ ~CBrushT()
+ {
+ if(t_bManaged && m_hBrush != NULL)
+ DeleteObject();
+ }
+
+ CBrushT<t_bManaged>& operator =(HBRUSH hBrush)
+ {
+ Attach(hBrush);
+ return *this;
+ }
+
+ void Attach(HBRUSH hBrush)
+ {
+ if(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush)
+ ::DeleteObject(m_hBrush);
+ m_hBrush = hBrush;
+ }
+
+ HBRUSH Detach()
+ {
+ HBRUSH hBrush = m_hBrush;
+ m_hBrush = NULL;
+ return hBrush;
+ }
+
+ operator HBRUSH() const { return m_hBrush; }
+
+ bool IsNull() const { return (m_hBrush == NULL); }
+
+// Create methods
+ HBRUSH CreateSolidBrush(COLORREF crColor)
+ {
+ ATLASSERT(m_hBrush == NULL);
+ m_hBrush = ::CreateSolidBrush(crColor);
+ return m_hBrush;
+ }
+
+#ifndef _WIN32_WCE
+ HBRUSH CreateHatchBrush(int nIndex, COLORREF crColor)
+ {
+ ATLASSERT(m_hBrush == NULL);
+ m_hBrush = ::CreateHatchBrush(nIndex, crColor);
+ return m_hBrush;
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+ HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush)
+ {
+ ATLASSERT(m_hBrush == NULL);
+#ifndef _WIN32_WCE
+ m_hBrush = ::CreateBrushIndirect(lpLogBrush);
+#else // CE specific
+ m_hBrush = ATL::CreateBrushIndirect(lpLogBrush);
+#endif // _WIN32_WCE
+ return m_hBrush;
+ }
+#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+
+ HBRUSH CreatePatternBrush(HBITMAP hBitmap)
+ {
+ ATLASSERT(m_hBrush == NULL);
+ m_hBrush = ::CreatePatternBrush(hBitmap);
+ return m_hBrush;
+ }
+
+ HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage)
+ {
+ ATLASSERT(hPackedDIB != NULL);
+ const void* lpPackedDIB = GlobalLock(hPackedDIB);
+ ATLASSERT(lpPackedDIB != NULL);
+ m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
+ GlobalUnlock(hPackedDIB);
+ return m_hBrush;
+ }
+
+ HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage)
+ {
+ ATLASSERT(m_hBrush == NULL);
+ m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
+ return m_hBrush;
+ }
+
+ HBRUSH CreateSysColorBrush(int nIndex)
+ {
+ ATLASSERT(m_hBrush == NULL);
+ m_hBrush = ::GetSysColorBrush(nIndex);
+ return m_hBrush;
+ }
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hBrush != NULL);
+ BOOL bRet = ::DeleteObject(m_hBrush);
+ if(bRet)
+ m_hBrush = NULL;
+ return bRet;
+ }
+
+// Attributes
+ int GetLogBrush(LOGBRUSH* pLogBrush) const
+ {
+ ATLASSERT(m_hBrush != NULL);
+ return ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush);
+ }
+
+ bool GetLogBrush(LOGBRUSH& LogBrush) const
+ {
+ ATLASSERT(m_hBrush != NULL);
+ return (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH));
+ }
+};
+
+typedef CBrushT<false> CBrushHandle;
+typedef CBrushT<true> CBrush;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFont
+
+class CLogFont : public LOGFONT
+{
+public:
+ CLogFont()
+ {
+ memset(this, 0, sizeof(LOGFONT));
+ }
+
+ CLogFont(const LOGFONT& lf)
+ {
+ Copy(&lf);
+ }
+
+ CLogFont(HFONT hFont)
+ {
+ ATLASSERT(::GetObjectType(hFont) == OBJ_FONT);
+ ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
+ }
+
+ HFONT CreateFontIndirect()
+ {
+ return ::CreateFontIndirect(this);
+ }
+
+ void SetBold()
+ {
+ lfWeight = FW_BOLD;
+ }
+
+ bool IsBold() const
+ {
+ return (lfWeight >= FW_BOLD);
+ }
+
+ void MakeBolder(int iScale = 1)
+ {
+ lfWeight += FW_BOLD * iScale;
+ }
+
+ void MakeLarger(int iScale)
+ {
+ if(lfHeight > 0)
+ lfHeight += iScale;
+ else
+ lfHeight -= iScale;
+ }
+
+ void SetHeight(LONG nPointSize, HDC hDC = NULL)
+ {
+ HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);
+ // For MM_TEXT mapping mode
+ lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC1, LOGPIXELSY), 72);
+ if(hDC == NULL)
+ ::ReleaseDC(NULL, hDC1);
+ }
+
+ LONG GetHeight(HDC hDC = NULL) const
+ {
+ HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);
+ // For MM_TEXT mapping mode
+ LONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC1, LOGPIXELSY));
+ if(hDC == NULL)
+ ::ReleaseDC(NULL, hDC1);
+
+ return nPointSize;
+ }
+
+ LONG GetDeciPointHeight(HDC hDC = NULL) const
+ {
+ HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);
+#ifndef _WIN32_WCE
+ POINT ptOrg = { 0, 0 };
+ ::DPtoLP(hDC1, &ptOrg, 1);
+ POINT pt = { 0, 0 };
+ pt.y = abs(lfHeight) + ptOrg.y;
+ ::LPtoDP(hDC1, &pt,1);
+ LONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point
+#else // CE specific
+ // DP and LP are always the same on CE
+ LONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point
+#endif // _WIN32_WCE
+ if(hDC == NULL)
+ ::ReleaseDC(NULL, hDC1);
+
+ return nDeciPoint;
+ }
+
+ void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL)
+ {
+ HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);
+#ifndef _WIN32_WCE
+ POINT pt = { 0, 0 };
+ pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720); // 72 points/inch, 10 decipoints/point
+ ::DPtoLP(hDC1, &pt, 1);
+ POINT ptOrg = { 0, 0 };
+ ::DPtoLP(hDC1, &ptOrg, 1);
+ lfHeight = -abs(pt.y - ptOrg.y);
+#else // CE specific
+ // DP and LP are always the same on CE
+ lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720)); // 72 points/inch, 10 decipoints/point
+#endif // _WIN32_WCE
+ if(hDC == NULL)
+ ::ReleaseDC(NULL, hDC1);
+ }
+
+#ifndef _WIN32_WCE
+ void SetCaptionFont()
+ {
+ NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));
+ Copy(&ncm.lfCaptionFont);
+ }
+
+ void SetMenuFont()
+ {
+ NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));
+ Copy(&ncm.lfMenuFont);
+ }
+
+ void SetStatusFont()
+ {
+ NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));
+ Copy(&ncm.lfStatusFont);
+ }
+
+ void SetMessageBoxFont()
+ {
+ NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
+ ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));
+ Copy(&ncm.lfMessageFont);
+ }
+#endif // !_WIN32_WCE
+
+ void Copy(const LOGFONT* pLogFont)
+ {
+ ATLASSERT(pLogFont != NULL);
+ *(LOGFONT*)this = *pLogFont;
+ }
+
+ CLogFont& operator =(const CLogFont& src)
+ {
+ Copy(&src);
+ return *this;
+ }
+
+ CLogFont& operator =(const LOGFONT& src)
+ {
+ Copy(&src);
+ return *this;
+ }
+
+ CLogFont& operator =(HFONT hFont)
+ {
+ ATLASSERT(::GetObjectType(hFont) == OBJ_FONT);
+ ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
+ return *this;
+ }
+
+ bool operator ==(const LOGFONT& logfont) const
+ {
+ return(logfont.lfHeight == lfHeight &&
+ logfont.lfWidth == lfWidth &&
+ logfont.lfEscapement == lfEscapement &&
+ logfont.lfOrientation == lfOrientation &&
+ logfont.lfWeight == lfWeight &&
+ logfont.lfItalic == lfItalic &&
+ logfont.lfUnderline == lfUnderline &&
+ logfont.lfStrikeOut == lfStrikeOut &&
+ logfont.lfCharSet == lfCharSet &&
+ logfont.lfOutPrecision == lfOutPrecision &&
+ logfont.lfClipPrecision == lfClipPrecision &&
+ logfont.lfQuality == lfQuality &&
+ logfont.lfPitchAndFamily == lfPitchAndFamily &&
+ lstrcmp(logfont.lfFaceName, lfFaceName) == 0);
+ }
+};
+
+
+template <bool t_bManaged>
+class CFontT
+{
+public:
+// Data members
+ HFONT m_hFont;
+
+// Constructor/destructor/operators
+ CFontT(HFONT hFont = NULL) : m_hFont(hFont)
+ { }
+
+ ~CFontT()
+ {
+ if(t_bManaged && m_hFont != NULL)
+ DeleteObject();
+ }
+
+ CFontT<t_bManaged>& operator =(HFONT hFont)
+ {
+ Attach(hFont);
+ return *this;
+ }
+
+ void Attach(HFONT hFont)
+ {
+ if(t_bManaged && m_hFont != NULL && m_hFont != hFont)
+ ::DeleteObject(m_hFont);
+ m_hFont = hFont;
+ }
+
+ HFONT Detach()
+ {
+ HFONT hFont = m_hFont;
+ m_hFont = NULL;
+ return hFont;
+ }
+
+ operator HFONT() const { return m_hFont; }
+
+ bool IsNull() const { return (m_hFont == NULL); }
+
+// Create methods
+ HFONT CreateFontIndirect(const LOGFONT* lpLogFont)
+ {
+ ATLASSERT(m_hFont == NULL);
+ m_hFont = ::CreateFontIndirect(lpLogFont);
+ return m_hFont;
+ }
+
+#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)
+ HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex)
+ {
+ ATLASSERT(m_hFont == NULL);
+ m_hFont = ::CreateFontIndirectEx(penumlfex);
+ return m_hFont;
+ }
+#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)
+
+#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+ HFONT CreateFont(int nHeight, int nWidth, int nEscapement,
+ int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline,
+ BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision,
+ BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily,
+ LPCTSTR lpszFacename)
+ {
+ ATLASSERT(m_hFont == NULL);
+#ifndef _WIN32_WCE
+ m_hFont = ::CreateFont(nHeight, nWidth, nEscapement,
+ nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
+ nCharSet, nOutPrecision, nClipPrecision, nQuality,
+ nPitchAndFamily, lpszFacename);
+#else // CE specific
+ m_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement,
+ nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
+ nCharSet, nOutPrecision, nClipPrecision, nQuality,
+ nPitchAndFamily, lpszFacename);
+#endif // _WIN32_WCE
+ return m_hFont;
+ }
+#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
+
+ HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false)
+ {
+ LOGFONT logFont = { 0 };
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ logFont.lfHeight = nPointSize;
+ SecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE);
+
+ if(bBold)
+ logFont.lfWeight = FW_BOLD;
+ if(bItalic)
+ logFont.lfItalic = (BYTE)TRUE;
+
+ return CreatePointFontIndirect(&logFont, hDC);
+ }
+
+ HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL)
+ {
+ HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);
+
+ // convert nPointSize to logical units based on hDC
+ LOGFONT logFont = *lpLogFont;
+#ifndef _WIN32_WCE
+ POINT pt = { 0, 0 };
+ pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720); // 72 points/inch, 10 decipoints/point
+ ::DPtoLP(hDC1, &pt, 1);
+ POINT ptOrg = { 0, 0 };
+ ::DPtoLP(hDC1, &ptOrg, 1);
+ logFont.lfHeight = -abs(pt.y - ptOrg.y);
+#else // CE specific
+ // DP and LP are always the same on CE
+ logFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720)); // 72 points/inch, 10 decipoints/point
+#endif // _WIN32_WCE
+
+ if(hDC == NULL)
+ ::ReleaseDC(NULL, hDC1);
+
+ return CreateFontIndirect(&logFont);
+ }
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hFont != NULL);
+ BOOL bRet = ::DeleteObject(m_hFont);
+ if(bRet)
+ m_hFont = NULL;
+ return bRet;
+ }
+
+// Attributes
+ int GetLogFont(LOGFONT* pLogFont) const
+ {
+ ATLASSERT(m_hFont != NULL);
+ return ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont);
+ }
+
+ bool GetLogFont(LOGFONT& LogFont) const
+ {
+ ATLASSERT(m_hFont != NULL);
+ return (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT));
+ }
+};
+
+typedef CFontT<false> CFontHandle;
+typedef CFontT<true> CFont;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBitmap
+
+template <bool t_bManaged>
+class CBitmapT
+{
+public:
+// Data members
+ HBITMAP m_hBitmap;
+
+// Constructor/destructor/operators
+ CBitmapT(HBITMAP hBitmap = NULL) : m_hBitmap(hBitmap)
+ { }
+
+ ~CBitmapT()
+ {
+ if(t_bManaged && m_hBitmap != NULL)
+ DeleteObject();
+ }
+
+ CBitmapT<t_bManaged>& operator =(HBITMAP hBitmap)
+ {
+ Attach(hBitmap);
+ return *this;
+ }
+
+ void Attach(HBITMAP hBitmap)
+ {
+ if(t_bManaged && m_hBitmap != NULL&& m_hBitmap != hBitmap)
+ ::DeleteObject(m_hBitmap);
+ m_hBitmap = hBitmap;
+ }
+
+ HBITMAP Detach()
+ {
+ HBITMAP hBitmap = m_hBitmap;
+ m_hBitmap = NULL;
+ return hBitmap;
+ }
+
+ operator HBITMAP() const { return m_hBitmap; }
+
+ bool IsNull() const { return (m_hBitmap == NULL); }
+
+// Create and load methods
+ HBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr);
+ return m_hBitmap;
+ }
+
+ HBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap));
+ return m_hBitmap;
+ }
+
+#ifndef _WIN32_WCE
+ HBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize);
+ return m_hBitmap;
+ }
+#endif // !_WIN32_WCE
+
+ HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits);
+ return m_hBitmap;
+ }
+
+#ifndef _WIN32_WCE
+ HBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateBitmapIndirect(lpBitmap);
+ return m_hBitmap;
+ }
+#endif // !_WIN32_WCE
+
+ HBITMAP CreateCompatibleBitmap(HDC hDC, int nWidth, int nHeight)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight);
+ return m_hBitmap;
+ }
+
+#ifndef _WIN32_WCE
+ HBITMAP CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateDiscardableBitmap(hDC, nWidth, nHeight);
+ return m_hBitmap;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ BOOL bRet = ::DeleteObject(m_hBitmap);
+ if(bRet)
+ m_hBitmap = NULL;
+ return bRet;
+ }
+
+// Attributes
+ int GetBitmap(BITMAP* pBitMap) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::GetObject(m_hBitmap, sizeof(BITMAP), pBitMap);
+ }
+
+ bool GetBitmap(BITMAP& bm) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return (::GetObject(m_hBitmap, sizeof(BITMAP), &bm) == sizeof(BITMAP));
+ }
+
+ bool GetSize(SIZE& size) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ BITMAP bm = { 0 };
+ if(!GetBitmap(&bm))
+ return false;
+ size.cx = bm.bmWidth;
+ size.cy = bm.bmHeight;
+ return true;
+ }
+
+#ifndef _WIN32_WCE
+ DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::GetBitmapBits(m_hBitmap, dwCount, lpBits);
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
+ DWORD SetBitmapBits(DWORD dwCount, const void* lpBits)
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::SetBitmapBits(m_hBitmap, dwCount, lpBits);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
+
+#ifndef _WIN32_WCE
+ BOOL GetBitmapDimension(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::GetBitmapDimensionEx(m_hBitmap, lpSize);
+ }
+
+ BOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL)
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::SetBitmapDimensionEx(m_hBitmap, nWidth, nHeight, lpSize);
+ }
+
+// DIB support
+ HBITMAP CreateDIBitmap(HDC hDC, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateDIBitmap(hDC, lpbmih, dwInit, lpbInit, lpbmi, uColorUse);
+ return m_hBitmap;
+ }
+#endif // !_WIN32_WCE
+
+ HBITMAP CreateDIBSection(HDC hDC, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset)
+ {
+ ATLASSERT(m_hBitmap == NULL);
+ m_hBitmap = ::CreateDIBSection(hDC, lpbmi, uColorUse, ppvBits, hSection, dwOffset);
+ return m_hBitmap;
+ }
+
+#ifndef _WIN32_WCE
+ int GetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::GetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);
+ }
+
+ int SetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse)
+ {
+ ATLASSERT(m_hBitmap != NULL);
+ return ::SetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);
+ }
+#endif // !_WIN32_WCE
+};
+
+typedef CBitmapT<false> CBitmapHandle;
+typedef CBitmapT<true> CBitmap;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPalette
+
+template <bool t_bManaged>
+class CPaletteT
+{
+public:
+// Data members
+ HPALETTE m_hPalette;
+
+// Constructor/destructor/operators
+ CPaletteT(HPALETTE hPalette = NULL) : m_hPalette(hPalette)
+ { }
+
+ ~CPaletteT()
+ {
+ if(t_bManaged && m_hPalette != NULL)
+ DeleteObject();
+ }
+
+ CPaletteT<t_bManaged>& operator =(HPALETTE hPalette)
+ {
+ Attach(hPalette);
+ return *this;
+ }
+
+ void Attach(HPALETTE hPalette)
+ {
+ if(t_bManaged && m_hPalette != NULL && m_hPalette != hPalette)
+ ::DeleteObject(m_hPalette);
+ m_hPalette = hPalette;
+ }
+
+ HPALETTE Detach()
+ {
+ HPALETTE hPalette = m_hPalette;
+ m_hPalette = NULL;
+ return hPalette;
+ }
+
+ operator HPALETTE() const { return m_hPalette; }
+
+ bool IsNull() const { return (m_hPalette == NULL); }
+
+// Create methods
+ HPALETTE CreatePalette(LPLOGPALETTE lpLogPalette)
+ {
+ ATLASSERT(m_hPalette == NULL);
+ m_hPalette = ::CreatePalette(lpLogPalette);
+ return m_hPalette;
+ }
+
+#ifndef _WIN32_WCE
+ HPALETTE CreateHalftonePalette(HDC hDC)
+ {
+ ATLASSERT(m_hPalette == NULL);
+ ATLASSERT(hDC != NULL);
+ m_hPalette = ::CreateHalftonePalette(hDC);
+ return m_hPalette;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hPalette != NULL);
+ BOOL bRet = ::DeleteObject(m_hPalette);
+ if(bRet)
+ m_hPalette = NULL;
+ return bRet;
+ }
+
+// Attributes
+ int GetEntryCount() const
+ {
+ ATLASSERT(m_hPalette != NULL);
+ WORD nEntries = 0;
+ ::GetObject(m_hPalette, sizeof(WORD), &nEntries);
+ return (int)nEntries;
+ }
+
+ UINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const
+ {
+ ATLASSERT(m_hPalette != NULL);
+ return ::GetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);
+ }
+
+ UINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)
+ {
+ ATLASSERT(m_hPalette != NULL);
+ return ::SetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);
+ }
+
+// Operations
+#ifndef _WIN32_WCE
+ void AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)
+ {
+ ATLASSERT(m_hPalette != NULL);
+ ::AnimatePalette(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);
+ }
+
+ BOOL ResizePalette(UINT nNumEntries)
+ {
+ ATLASSERT(m_hPalette != NULL);
+ return ::ResizePalette(m_hPalette, nNumEntries);
+ }
+#endif // !_WIN32_WCE
+
+ UINT GetNearestPaletteIndex(COLORREF crColor) const
+ {
+ ATLASSERT(m_hPalette != NULL);
+ return ::GetNearestPaletteIndex(m_hPalette, crColor);
+ }
+};
+
+typedef CPaletteT<false> CPaletteHandle;
+typedef CPaletteT<true> CPalette;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRgn
+
+template <bool t_bManaged>
+class CRgnT
+{
+public:
+// Data members
+ HRGN m_hRgn;
+
+// Constructor/destructor/operators
+ CRgnT(HRGN hRgn = NULL) : m_hRgn(hRgn)
+ { }
+
+ ~CRgnT()
+ {
+ if(t_bManaged && m_hRgn != NULL)
+ DeleteObject();
+ }
+
+ CRgnT<t_bManaged>& operator =(HRGN hRgn)
+ {
+ Attach(hRgn);
+ return *this;
+ }
+
+ void Attach(HRGN hRgn)
+ {
+ if(t_bManaged && m_hRgn != NULL && m_hRgn != hRgn)
+ ::DeleteObject(m_hRgn);
+ m_hRgn = hRgn;
+ }
+
+ HRGN Detach()
+ {
+ HRGN hRgn = m_hRgn;
+ m_hRgn = NULL;
+ return hRgn;
+ }
+
+ operator HRGN() const { return m_hRgn; }
+
+ bool IsNull() const { return (m_hRgn == NULL); }
+
+// Create methods
+ HRGN CreateRectRgn(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreateRectRgn(x1, y1, x2, y2);
+ return m_hRgn;
+ }
+
+ HRGN CreateRectRgnIndirect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreateRectRgnIndirect(lpRect);
+ return m_hRgn;
+ }
+
+#ifndef _WIN32_WCE
+ HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreateEllipticRgn(x1, y1, x2, y2);
+ return m_hRgn;
+ }
+
+ HRGN CreateEllipticRgnIndirect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreateEllipticRgnIndirect(lpRect);
+ return m_hRgn;
+ }
+
+ HRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreatePolygonRgn(lpPoints, nCount, nMode);
+ return m_hRgn;
+ }
+
+ HRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode);
+ return m_hRgn;
+ }
+
+ HRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3);
+ return m_hRgn;
+ }
+
+ HRGN CreateFromPath(HDC hDC)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ ATLASSERT(hDC != NULL);
+ m_hRgn = ::PathToRegion(hDC);
+ return m_hRgn;
+ }
+
+ HRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData)
+ {
+ ATLASSERT(m_hRgn == NULL);
+ m_hRgn = ::ExtCreateRegion(lpXForm, nCount, pRgnData);
+ return m_hRgn;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hRgn != NULL);
+ BOOL bRet = ::DeleteObject(m_hRgn);
+ if(bRet)
+ m_hRgn = NULL;
+ return bRet;
+ }
+
+// Operations
+ void SetRectRgn(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ ::SetRectRgn(m_hRgn, x1, y1, x2, y2);
+ }
+
+ void SetRectRgn(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ ::SetRectRgn(m_hRgn, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
+ }
+
+ int CombineRgn(HRGN hRgnSrc1, HRGN hRgnSrc2, int nCombineMode)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::CombineRgn(m_hRgn, hRgnSrc1, hRgnSrc2, nCombineMode);
+ }
+
+ int CombineRgn(HRGN hRgnSrc, int nCombineMode)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::CombineRgn(m_hRgn, m_hRgn, hRgnSrc, nCombineMode);
+ }
+
+ int CopyRgn(HRGN hRgnSrc)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::CombineRgn(m_hRgn, hRgnSrc, NULL, RGN_COPY);
+ }
+
+ BOOL EqualRgn(HRGN hRgn) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::EqualRgn(m_hRgn, hRgn);
+ }
+
+ int OffsetRgn(int x, int y)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::OffsetRgn(m_hRgn, x, y);
+ }
+
+ int OffsetRgn(POINT point)
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::OffsetRgn(m_hRgn, point.x, point.y);
+ }
+
+ int GetRgnBox(LPRECT lpRect) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::GetRgnBox(m_hRgn, lpRect);
+ }
+
+ BOOL PtInRegion(int x, int y) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::PtInRegion(m_hRgn, x, y);
+ }
+
+ BOOL PtInRegion(POINT point) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::PtInRegion(m_hRgn, point.x, point.y);
+ }
+
+ BOOL RectInRegion(LPCRECT lpRect) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return ::RectInRegion(m_hRgn, lpRect);
+ }
+
+ int GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const
+ {
+ ATLASSERT(m_hRgn != NULL);
+ return (int)::GetRegionData(m_hRgn, nDataSize, lpRgnData);
+ }
+};
+
+typedef CRgnT<false> CRgnHandle;
+typedef CRgnT<true> CRgn;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDC - The device context class
+
+template <bool t_bManaged>
+class CDCT
+{
+public:
+// Data members
+ HDC m_hDC;
+
+// Constructor/destructor/operators
+ CDCT(HDC hDC = NULL) : m_hDC(hDC)
+ {
+ }
+
+ ~CDCT()
+ {
+ if(t_bManaged && m_hDC != NULL)
+ ::DeleteDC(Detach());
+ }
+
+ CDCT<t_bManaged>& operator =(HDC hDC)
+ {
+ Attach(hDC);
+ return *this;
+ }
+
+ void Attach(HDC hDC)
+ {
+ if(t_bManaged && m_hDC != NULL && m_hDC != hDC)
+ ::DeleteDC(m_hDC);
+ m_hDC = hDC;
+ }
+
+ HDC Detach()
+ {
+ HDC hDC = m_hDC;
+ m_hDC = NULL;
+ return hDC;
+ }
+
+ operator HDC() const { return m_hDC; }
+
+ bool IsNull() const { return (m_hDC == NULL); }
+
+// Operations
+#ifndef _WIN32_WCE
+ HWND WindowFromDC() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::WindowFromDC(m_hDC);
+ }
+#endif // !_WIN32_WCE
+
+ CPenHandle GetCurrentPen() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return CPenHandle((HPEN)::GetCurrentObject(m_hDC, OBJ_PEN));
+ }
+
+ CBrushHandle GetCurrentBrush() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return CBrushHandle((HBRUSH)::GetCurrentObject(m_hDC, OBJ_BRUSH));
+ }
+
+ CPaletteHandle GetCurrentPalette() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return CPaletteHandle((HPALETTE)::GetCurrentObject(m_hDC, OBJ_PAL));
+ }
+
+ CFontHandle GetCurrentFont() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT));
+ }
+
+ CBitmapHandle GetCurrentBitmap() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return CBitmapHandle((HBITMAP)::GetCurrentObject(m_hDC, OBJ_BITMAP));
+ }
+
+ HDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData)
+ {
+ ATLASSERT(m_hDC == NULL);
+ m_hDC = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData);
+ return m_hDC;
+ }
+
+ HDC CreateCompatibleDC(HDC hDC = NULL)
+ {
+ ATLASSERT(m_hDC == NULL);
+ m_hDC = ::CreateCompatibleDC(hDC);
+ return m_hDC;
+ }
+
+ BOOL DeleteDC()
+ {
+ if(m_hDC == NULL)
+ return FALSE;
+ BOOL bRet = ::DeleteDC(m_hDC);
+ if(bRet)
+ m_hDC = NULL;
+ return bRet;
+ }
+
+// Device-Context Functions
+ int SaveDC()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SaveDC(m_hDC);
+ }
+
+ BOOL RestoreDC(int nSavedDC)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::RestoreDC(m_hDC, nSavedDC);
+ }
+
+ int GetDeviceCaps(int nIndex) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetDeviceCaps(m_hDC, nIndex);
+ }
+
+#ifndef _WIN32_WCE
+ UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetBoundsRect(m_hDC, lpRectBounds, flags);
+ }
+
+ UINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetBoundsRect(m_hDC, lpRectBounds, flags);
+ }
+
+ BOOL ResetDC(const DEVMODE* lpDevMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ResetDC(m_hDC, lpDevMode) != NULL;
+ }
+
+// Drawing-Tool Functions
+ BOOL GetBrushOrg(LPPOINT lpPoint) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetBrushOrgEx(m_hDC, lpPoint);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetBrushOrgEx(m_hDC, x, y, lpPoint);
+ }
+
+ BOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetBrushOrgEx(m_hDC, point.x, point.y, lpPointRet);
+ }
+
+#ifndef _WIN32_WCE
+ int EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifdef STRICT
+ return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, lpData);
+#else
+ return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData);
+#endif
+ }
+#endif // !_WIN32_WCE
+
+// Type-safe selection helpers
+ HPEN SelectPen(HPEN hPen)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifndef _WIN32_WCE
+ ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN || ::GetObjectType(hPen) == OBJ_EXTPEN);
+#else // CE specific
+ ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN);
+#endif // _WIN32_WCE
+ return (HPEN)::SelectObject(m_hDC, hPen);
+ }
+
+ HBRUSH SelectBrush(HBRUSH hBrush)
+ {
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(hBrush == NULL || ::GetObjectType(hBrush) == OBJ_BRUSH);
+ return (HBRUSH)::SelectObject(m_hDC, hBrush);
+ }
+
+ HFONT SelectFont(HFONT hFont)
+ {
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT);
+ return (HFONT)::SelectObject(m_hDC, hFont);
+ }
+
+ HBITMAP SelectBitmap(HBITMAP hBitmap)
+ {
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP);
+ return (HBITMAP)::SelectObject(m_hDC, hBitmap);
+ }
+
+ int SelectRgn(HRGN hRgn) // special return for regions
+ {
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(hRgn == NULL || ::GetObjectType(hRgn) == OBJ_REGION);
+ return PtrToInt(::SelectObject(m_hDC, hRgn));
+ }
+
+// Type-safe selection helpers for stock objects
+ HPEN SelectStockPen(int nPen)
+ {
+ ATLASSERT(m_hDC != NULL);
+#if (_WIN32_WINNT >= 0x0500)
+ ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);
+#else
+ ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);
+#endif // !(_WIN32_WINNT >= 0x0500)
+ return SelectPen((HPEN)::GetStockObject(nPen));
+ }
+
+ HBRUSH SelectStockBrush(int nBrush)
+ {
+#if (_WIN32_WINNT >= 0x0500)
+ ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);
+#else
+ ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);
+#endif // !(_WIN32_WINNT >= 0x0500)
+ return SelectBrush((HBRUSH)::GetStockObject(nBrush));
+ }
+
+ HFONT SelectStockFont(int nFont)
+ {
+#ifndef _WIN32_WCE
+ ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);
+#else // CE specific
+ ATLASSERT(nFont == SYSTEM_FONT);
+#endif // _WIN32_WCE
+ return SelectFont((HFONT)::GetStockObject(nFont));
+ }
+
+ HPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground)
+ {
+ ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
+ return SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground);
+ }
+
+// Color and Color Palette Functions
+ COLORREF GetNearestColor(COLORREF crColor) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetNearestColor(m_hDC, crColor);
+ }
+
+ HPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground)
+ {
+ ATLASSERT(m_hDC != NULL);
+
+ return ::SelectPalette(m_hDC, hPalette, bForceBackground);
+ }
+
+ UINT RealizePalette()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::RealizePalette(m_hDC);
+ }
+
+#ifndef _WIN32_WCE
+ void UpdateColors()
+ {
+ ATLASSERT(m_hDC != NULL);
+ ::UpdateColors(m_hDC);
+ }
+#endif // !_WIN32_WCE
+
+// Drawing-Attribute Functions
+ COLORREF GetBkColor() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetBkColor(m_hDC);
+ }
+
+ int GetBkMode() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetBkMode(m_hDC);
+ }
+
+#ifndef _WIN32_WCE
+ int GetPolyFillMode() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetPolyFillMode(m_hDC);
+ }
+
+ int GetROP2() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetROP2(m_hDC);
+ }
+
+ int GetStretchBltMode() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetStretchBltMode(m_hDC);
+ }
+#endif // !_WIN32_WCE
+
+ COLORREF GetTextColor() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextColor(m_hDC);
+ }
+
+ COLORREF SetBkColor(COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetBkColor(m_hDC, crColor);
+ }
+
+ int SetBkMode(int nBkMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetBkMode(m_hDC, nBkMode);
+ }
+
+#ifndef _WIN32_WCE
+ int SetPolyFillMode(int nPolyFillMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPolyFillMode(m_hDC, nPolyFillMode);
+ }
+#endif // !_WIN32_WCE
+
+ int SetROP2(int nDrawMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetROP2(m_hDC, nDrawMode);
+ }
+
+#ifndef _WIN32_WCE
+ int SetStretchBltMode(int nStretchMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetStretchBltMode(m_hDC, nStretchMode);
+ }
+#endif // !_WIN32_WCE
+
+ COLORREF SetTextColor(COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetTextColor(m_hDC, crColor);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetColorAdjustment(m_hDC, lpColorAdjust);
+ }
+
+ BOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetColorAdjustment(m_hDC, lpColorAdjust);
+ }
+
+// Mapping Functions
+ int GetMapMode() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetMapMode(m_hDC);
+ }
+
+ BOOL GetViewportOrg(LPPOINT lpPoint) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetViewportOrgEx(m_hDC, lpPoint);
+ }
+
+ int SetMapMode(int nMapMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetMapMode(m_hDC, nMapMode);
+ }
+#endif // !_WIN32_WCE
+
+ // Viewport Origin
+ BOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetViewportOrgEx(m_hDC, x, y, lpPoint);
+ }
+
+ BOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return SetViewportOrg(point.x, point.y, lpPointRet);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, lpPoint);
+ }
+
+ // Viewport Extent
+ BOOL GetViewportExt(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetViewportExtEx(m_hDC, lpSize);
+ }
+
+ BOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetViewportExtEx(m_hDC, x, y, lpSize);
+ }
+
+ BOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return SetViewportExt(size.cx, size.cy, lpSizeRet);
+ }
+
+ BOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize);
+ }
+#endif // !_WIN32_WCE
+
+ // Window Origin
+#ifndef _WIN32_WCE
+ BOOL GetWindowOrg(LPPOINT lpPoint) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetWindowOrgEx(m_hDC, lpPoint);
+ }
+
+ BOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetWindowOrgEx(m_hDC, x, y, lpPoint);
+ }
+
+ BOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return SetWindowOrg(point.x, point.y, lpPointRet);
+ }
+
+ BOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::OffsetWindowOrgEx(m_hDC, nWidth, nHeight, lpPoint);
+ }
+
+ // Window extent
+ BOOL GetWindowExt(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetWindowExtEx(m_hDC, lpSize);
+ }
+
+ BOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetWindowExtEx(m_hDC, x, y, lpSize);
+ }
+
+ BOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return SetWindowExt(size.cx, size.cy, lpSizeRet);
+ }
+
+ BOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ScaleWindowExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize);
+ }
+
+// Coordinate Functions
+ BOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DPtoLP(m_hDC, lpPoints, nCount);
+ }
+
+ BOOL DPtoLP(LPRECT lpRect) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DPtoLP(m_hDC, (LPPOINT)lpRect, 2);
+ }
+
+ BOOL DPtoLP(LPSIZE lpSize) const
+ {
+ SIZE sizeWinExt = { 0, 0 };
+ if(!GetWindowExt(&sizeWinExt))
+ return FALSE;
+ SIZE sizeVpExt = { 0, 0 };
+ if(!GetViewportExt(&sizeVpExt))
+ return FALSE;
+ lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx));
+ lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy));
+ return TRUE;
+ }
+
+ BOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::LPtoDP(m_hDC, lpPoints, nCount);
+ }
+
+ BOOL LPtoDP(LPRECT lpRect) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::LPtoDP(m_hDC, (LPPOINT)lpRect, 2);
+ }
+
+ BOOL LPtoDP(LPSIZE lpSize) const
+ {
+ SIZE sizeWinExt = { 0, 0 };
+ if(!GetWindowExt(&sizeWinExt))
+ return FALSE;
+ SIZE sizeVpExt = { 0, 0 };
+ if(!GetViewportExt(&sizeVpExt))
+ return FALSE;
+ lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx));
+ lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy));
+ return TRUE;
+ }
+
+// Special Coordinate Functions (useful for dealing with metafiles and OLE)
+ #define HIMETRIC_INCH 2540 // HIMETRIC units per inch
+
+ void DPtoHIMETRIC(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ int nMapMode;
+ if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)
+ {
+ // when using a constrained map mode, map against physical inch
+ ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC);
+ DPtoLP(lpSize);
+ ((CDCHandle*)this)->SetMapMode(nMapMode);
+ }
+ else
+ {
+ // map against logical inch for non-constrained mapping modes
+ int cxPerInch = GetDeviceCaps(LOGPIXELSX);
+ int cyPerInch = GetDeviceCaps(LOGPIXELSY);
+ ATLASSERT(cxPerInch != 0 && cyPerInch != 0);
+ lpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch);
+ lpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch);
+ }
+ }
+
+ void HIMETRICtoDP(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ int nMapMode;
+ if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)
+ {
+ // when using a constrained map mode, map against physical inch
+ ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC);
+ LPtoDP(lpSize);
+ ((CDCHandle*)this)->SetMapMode(nMapMode);
+ }
+ else
+ {
+ // map against logical inch for non-constrained mapping modes
+ int cxPerInch = GetDeviceCaps(LOGPIXELSX);
+ int cyPerInch = GetDeviceCaps(LOGPIXELSY);
+ ATLASSERT(cxPerInch != 0 && cyPerInch != 0);
+ lpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH);
+ lpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH);
+ }
+ }
+
+ void LPtoHIMETRIC(LPSIZE lpSize) const
+ {
+ LPtoDP(lpSize);
+ DPtoHIMETRIC(lpSize);
+ }
+
+ void HIMETRICtoLP(LPSIZE lpSize) const
+ {
+ HIMETRICtoDP(lpSize);
+ DPtoLP(lpSize);
+ }
+#endif // !_WIN32_WCE
+
+// Region Functions
+ BOOL FillRgn(HRGN hRgn, HBRUSH hBrush)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FillRgn(m_hDC, hRgn, hBrush);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL FrameRgn(HRGN hRgn, HBRUSH hBrush, int nWidth, int nHeight)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FrameRgn(m_hDC, hRgn, hBrush, nWidth, nHeight);
+ }
+
+ BOOL InvertRgn(HRGN hRgn)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::InvertRgn(m_hDC, hRgn);
+ }
+
+ BOOL PaintRgn(HRGN hRgn)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PaintRgn(m_hDC, hRgn);
+ }
+#endif // !_WIN32_WCE
+
+// Clipping Functions
+ int GetClipBox(LPRECT lpRect) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetClipBox(m_hDC, lpRect);
+ }
+
+ int GetClipRgn(CRgn& region) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(region.IsNull())
+ region.CreateRectRgn(0, 0, 0, 0);
+
+ int nRet = ::GetClipRgn(m_hDC, region);
+ if(nRet != 1)
+ region.DeleteObject();
+
+ return nRet;
+ }
+
+#ifndef _WIN32_WCE
+ BOOL PtVisible(int x, int y) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PtVisible(m_hDC, x, y);
+ }
+
+ BOOL PtVisible(POINT point) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PtVisible(m_hDC, point.x, point.y);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL RectVisible(LPCRECT lpRect) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::RectVisible(m_hDC, lpRect);
+ }
+
+ int SelectClipRgn(HRGN hRgn)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SelectClipRgn(m_hDC, (HRGN)hRgn);
+ }
+
+ int ExcludeClipRect(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExcludeClipRect(m_hDC, x1, y1, x2, y2);
+ }
+
+ int ExcludeClipRect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExcludeClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
+ }
+
+#ifndef _WIN32_WCE
+ int ExcludeUpdateRgn(HWND hWnd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExcludeUpdateRgn(m_hDC, hWnd);
+ }
+#endif // !_WIN32_WCE
+
+ int IntersectClipRect(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::IntersectClipRect(m_hDC, x1, y1, x2, y2);
+ }
+
+ int IntersectClipRect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::IntersectClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
+ }
+
+#ifndef _WIN32_WCE
+ int OffsetClipRgn(int x, int y)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::OffsetClipRgn(m_hDC, x, y);
+ }
+
+ int OffsetClipRgn(SIZE size)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::OffsetClipRgn(m_hDC, size.cx, size.cy);
+ }
+
+ int SelectClipRgn(HRGN hRgn, int nMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExtSelectClipRgn(m_hDC, hRgn, nMode);
+ }
+#endif // !_WIN32_WCE
+
+// Line-Output Functions
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+ BOOL GetCurrentPosition(LPPOINT lpPoint) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCurrentPositionEx(m_hDC, lpPoint);
+ }
+
+ BOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::MoveToEx(m_hDC, x, y, lpPoint);
+ }
+
+ BOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return MoveTo(point.x, point.y, lpPointRet);
+ }
+
+ BOOL LineTo(int x, int y)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::LineTo(m_hDC, x, y);
+ }
+
+ BOOL LineTo(POINT point)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return LineTo(point.x, point.y);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+
+#ifndef _WIN32_WCE
+ BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Arc(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+
+ BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Arc(m_hDC, lpRect->left, lpRect->top,
+ lpRect->right, lpRect->bottom, ptStart.x, ptStart.y,
+ ptEnd.x, ptEnd.y);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL Polyline(LPPOINT lpPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Polyline(m_hDC, lpPoints, nCount);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::AngleArc(m_hDC, x, y, nRadius, fStartAngle, fSweepAngle);
+ }
+
+ BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ArcTo(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+
+ BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ArcTo(lpRect->left, lpRect->top, lpRect->right,
+ lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
+ }
+
+ int GetArcDirection() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetArcDirection(m_hDC);
+ }
+
+ int SetArcDirection(int nArcDirection)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetArcDirection(m_hDC, nArcDirection);
+ }
+
+ BOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolyDraw(m_hDC, lpPoints, lpTypes, nCount);
+ }
+
+ BOOL PolylineTo(const POINT* lpPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolylineTo(m_hDC, lpPoints, nCount);
+ }
+
+ BOOL PolyPolyline(const POINT* lpPoints,
+ const DWORD* lpPolyPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolyPolyline(m_hDC, lpPoints, lpPolyPoints, nCount);
+ }
+
+ BOOL PolyBezier(const POINT* lpPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolyBezier(m_hDC, lpPoints, nCount);
+ }
+
+ BOOL PolyBezierTo(const POINT* lpPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolyBezierTo(m_hDC, lpPoints, nCount);
+ }
+#endif // !_WIN32_WCE
+
+// Simple Drawing Functions
+ BOOL FillRect(LPCRECT lpRect, HBRUSH hBrush)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FillRect(m_hDC, lpRect, hBrush);
+ }
+
+ BOOL FillRect(LPCRECT lpRect, int nColorIndex)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifndef _WIN32_WCE
+ return ::FillRect(m_hDC, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1));
+#else // CE specific
+ return ::FillRect(m_hDC, lpRect, ::GetSysColorBrush(nColorIndex));
+#endif // _WIN32_WCE
+ }
+
+#ifndef _WIN32_WCE
+ BOOL FrameRect(LPCRECT lpRect, HBRUSH hBrush)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FrameRect(m_hDC, lpRect, hBrush);
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)
+ BOOL InvertRect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::InvertRect(m_hDC, lpRect);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)
+
+ BOOL DrawIcon(int x, int y, HICON hIcon)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifndef _WIN32_WCE
+ return ::DrawIcon(m_hDC, x, y, hIcon);
+#else // CE specific
+ return ::DrawIconEx(m_hDC, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL);
+#endif // _WIN32_WCE
+ }
+
+ BOOL DrawIcon(POINT point, HICON hIcon)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifndef _WIN32_WCE
+ return ::DrawIcon(m_hDC, point.x, point.y, hIcon);
+#else // CE specific
+ return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL);
+#endif // _WIN32_WCE
+ }
+
+ BOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawIconEx(m_hDC, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
+ }
+
+ BOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH hBrush = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP);
+ }
+
+ BOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH hBrush = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON);
+ }
+
+ BOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH hBrush = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT));
+ }
+
+ BOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH hBrush = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawState(m_hDC, hBrush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX);
+ }
+#endif // !_WIN32_WCE
+
+// Ellipse and Polygon Functions
+#ifndef _WIN32_WCE
+ BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Chord(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+
+ BOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Chord(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
+ }
+#endif // !_WIN32_WCE
+
+ void DrawFocusRect(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ ::DrawFocusRect(m_hDC, lpRect);
+ }
+
+ BOOL Ellipse(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Ellipse(m_hDC, x1, y1, x2, y2);
+ }
+
+ BOOL Ellipse(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Pie(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+
+ BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Pie(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL Polygon(LPPOINT lpPoints, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Polygon(m_hDC, lpPoints, nCount);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL PolyPolygon(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PolyPolygon(m_hDC, lpPoints, lpPolyCounts, nCount);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL Rectangle(int x1, int y1, int x2, int y2)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Rectangle(m_hDC, x1, y1, x2, y2);
+ }
+
+ BOOL Rectangle(LPCRECT lpRect)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Rectangle(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
+ }
+
+ BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::RoundRect(m_hDC, x1, y1, x2, y2, x3, y3);
+ }
+
+ BOOL RoundRect(LPCRECT lpRect, POINT point)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::RoundRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y);
+ }
+
+// Bitmap Functions
+ BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PatBlt(m_hDC, x, y, nWidth, nHeight, dwRop);
+ }
+
+ BOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC,
+ int xSrc, int ySrc, DWORD dwRop)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::BitBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop);
+ }
+
+ BOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StretchBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop);
+ }
+
+ COLORREF GetPixel(int x, int y) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetPixel(m_hDC, x, y);
+ }
+
+ COLORREF GetPixel(POINT point) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetPixel(m_hDC, point.x, point.y);
+ }
+
+ COLORREF SetPixel(int x, int y, COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPixel(m_hDC, x, y, crColor);
+ }
+
+ COLORREF SetPixel(POINT point, COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPixel(m_hDC, point.x, point.y, crColor);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL FloodFill(int x, int y, COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FloodFill(m_hDC, x, y, crColor);
+ }
+
+ BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExtFloodFill(m_hDC, x, y, crColor, nFillType);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::MaskBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PlgBlt(m_hDC, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask);
+ }
+
+ BOOL SetPixelV(int x, int y, COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPixelV(m_hDC, x, y, crColor);
+ }
+
+ BOOL SetPixelV(POINT point, COLORREF crColor)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPixelV(m_hDC, point.x, point.y, crColor);
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)
+#ifndef _WIN32_WCE
+ BOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::TransparentBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);
+ }
+#else // CE specific
+ BOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::TransparentImage(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);
+ }
+#endif // _WIN32_WCE
+
+#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420))
+ BOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GradientFill(m_hDC, pVertices, nVertices, pMeshElements, nMeshElements, dwMode);
+ }
+
+ BOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal)
+ {
+ ATLASSERT(m_hDC != NULL);
+
+ TRIVERTEX arrTvx[2] = { { 0 }, { 0 } };
+
+ arrTvx[0].x = rect.left;
+ arrTvx[0].y = rect.top;
+ arrTvx[0].Red = MAKEWORD(0, GetRValue(clr1));
+ arrTvx[0].Green = MAKEWORD(0, GetGValue(clr1));
+ arrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1));
+ arrTvx[0].Alpha = 0;
+
+ arrTvx[1].x = rect.right;
+ arrTvx[1].y = rect.bottom;
+ arrTvx[1].Red = MAKEWORD(0, GetRValue(clr2));
+ arrTvx[1].Green = MAKEWORD(0, GetGValue(clr2));
+ arrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2));
+ arrTvx[1].Alpha = 0;
+
+ GRADIENT_RECT gr = { 0, 1 };
+
+ return ::GradientFill(m_hDC, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)
+ BOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::AlphaBlend(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)
+#endif // !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)
+
+// Extra bitmap functions
+ // Helper function for painting a disabled toolbar or menu bitmap
+ // This function can take either an HBITMAP (for SS) or a DC with
+ // the bitmap already painted (for cmdbar)
+ BOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc,
+ HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),
+ HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),
+ HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))
+ {
+ ATLASSERT(m_hDC != NULL || hBitmap != NULL);
+ ATLASSERT(nWidth > 0 && nHeight > 0);
+
+ // Create a generic DC for all BitBlts
+ CDCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(m_hDC);
+ ATLASSERT(dc.m_hDC != NULL);
+ if(dc.m_hDC == NULL)
+ return FALSE;
+
+ // Create a DC for the monochrome DIB section
+ CDC dcBW = ::CreateCompatibleDC(m_hDC);
+ ATLASSERT(dcBW.m_hDC != NULL);
+ if(dcBW.m_hDC == NULL)
+ {
+ if(hSrcDC == NULL)
+ dc.DeleteDC();
+ return FALSE;
+ }
+
+ // Create the monochrome DIB section with a black and white palette
+ struct RGBBWBITMAPINFO
+ {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[2];
+ };
+
+ RGBBWBITMAPINFO rgbBWBitmapInfo =
+ {
+ { sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 },
+ { { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } }
+ };
+
+ VOID* pbitsBW;
+ CBitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
+ ATLASSERT(bmpBW.m_hBitmap != NULL);
+ if(bmpBW.m_hBitmap == NULL)
+ {
+ if(hSrcDC == NULL)
+ dc.DeleteDC();
+ return FALSE;
+ }
+
+ // Attach the monochrome DIB section and the bitmap to the DCs
+ HBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW);
+ HBITMAP hbmOldDC = NULL;
+ if(hBitmap != NULL)
+ hbmOldDC = dc.SelectBitmap(hBitmap);
+
+ // Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white
+ {
+ CDC dcTemp1 = ::CreateCompatibleDC(m_hDC);
+ CDC dcTemp2 = ::CreateCompatibleDC(m_hDC);
+ CBitmap bmpTemp1;
+ bmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight);
+ CBitmap bmpTemp2;
+ bmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
+ HBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1);
+ HBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2);
+ // Let's copy our image, it will be altered
+ dcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY);
+
+ // All dark gray pixels will become white, the others black
+ dcTemp1.SetBkColor(RGB(128, 128, 128));
+ dcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);
+ // Do an XOR to set to black these white pixels
+ dcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT);
+
+ // BitBlt the bitmap into the monochrome DIB section
+ // The DIB section will do a true monochrome conversion
+ // The magenta background being closer to white will become white
+ dcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);
+
+ // Cleanup
+ dcTemp1.SelectBitmap(hOldBmp1);
+ dcTemp2.SelectBitmap(hOldBmp2);
+ }
+
+ // Paint the destination rectangle using hBrushBackground
+ if(hBrushBackground != NULL)
+ {
+ RECT rc = { x, y, x + nWidth, y + nHeight };
+ FillRect(&rc, hBrushBackground);
+ }
+
+ // BitBlt the black bits in the monochrome bitmap into hBrush3DEffect color in the destination DC
+ // The magic ROP comes from the Charles Petzold's book
+ HBRUSH hOldBrush = SelectBrush(hBrush3DEffect);
+ BitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);
+
+ // BitBlt the black bits in the monochrome bitmap into hBrushDisabledImage color in the destination DC
+ SelectBrush(hBrushDisabledImage);
+ BitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);
+
+ SelectBrush(hOldBrush);
+ dcBW.SelectBitmap(hbmOldBW);
+ dc.SelectBitmap(hbmOldDC);
+
+ if(hSrcDC == NULL)
+ dc.DeleteDC();
+
+ return TRUE;
+ }
+
+// Text Functions
+#ifndef _WIN32_WCE
+ BOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1)
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(nCount == -1)
+ nCount = lstrlen(lpszString);
+ return ::TextOut(m_hDC, x, y, lpszString, nCount);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(nCount == -1)
+ nCount = lstrlen(lpszString);
+ return ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths);
+ }
+
+#ifndef _WIN32_WCE
+ SIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0)
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(nCount == -1)
+ nCount = lstrlen(lpszString);
+ LONG lRes = ::TabbedTextOut(m_hDC, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin);
+ SIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) };
+ return size;
+ }
+#endif // !_WIN32_WCE
+
+ int DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)
+ {
+ ATLASSERT(m_hDC != NULL);
+#ifndef _WIN32_WCE
+ ATLASSERT((uFormat & DT_MODIFYSTRING) == 0);
+#endif // !_WIN32_WCE
+ return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat);
+ }
+
+ int DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat);
+ }
+
+#ifndef _WIN32_WCE
+ int DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawTextEx(m_hDC, lpstrText, cchText, lpRect, uFormat, lpDTParams);
+ }
+#endif // !_WIN32_WCE
+
+#if (_WIN32_WINNT >= 0x0501)
+ int DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset)
+ {
+ ATLASSERT(m_hDC != NULL);
+ // This function is present only if comctl32.dll version 6 is loaded;
+ // we use LoadLibrary/GetProcAddress to allow apps compiled with
+ // _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl
+ int nRet = 0;
+ HMODULE hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
+ ATLASSERT(hCommCtrlDLL != NULL);
+ if(hCommCtrlDLL != NULL)
+ {
+ typedef int (WINAPI *PFN_DrawShadowText)(HDC hDC, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset);
+ PFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, "DrawShadowText");
+ ATLASSERT(pfnDrawShadowText != NULL); // this function requires CommCtrl6
+ if(pfnDrawShadowText != NULL)
+ nRet = pfnDrawShadowText(m_hDC, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset);
+ ::FreeLibrary(hCommCtrlDLL);
+ }
+ return nRet;
+ }
+#endif // (_WIN32_WINNT >= 0x0501)
+
+ BOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(nCount == -1)
+ nCount = lstrlen(lpszString);
+ return ::GetTextExtentPoint32(m_hDC, lpszString, nCount, lpSize);
+ }
+
+ BOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextExtentExPoint(m_hDC, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
+ }
+
+#ifndef _WIN32_WCE
+ DWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(nCount == -1)
+ nCount = lstrlen(lpszString);
+ return ::GetTabbedTextExtent(m_hDC, lpszString, nCount, nTabPositions, lpnTabStopPositions);
+ }
+
+ BOOL GrayString(HBRUSH hBrush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GrayString(m_hDC, hBrush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight);
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+ UINT GetTextAlign() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextAlign(m_hDC);
+ }
+
+ UINT SetTextAlign(UINT nFlags)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetTextAlign(m_hDC, nFlags);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+
+ int GetTextFace(LPTSTR lpszFacename, int nCount) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextFace(m_hDC, nCount, lpszFacename);
+ }
+
+ int GetTextFaceLen() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextFace(m_hDC, 0, NULL);
+ }
+
+#ifndef _ATL_NO_COM
+#ifdef _OLEAUTO_H_
+ BOOL GetTextFace(BSTR& bstrFace) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(bstrFace == NULL);
+
+ int nLen = GetTextFaceLen();
+ if(nLen == 0)
+ return FALSE;
+
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpszText = buff.Allocate(nLen);
+ if(lpszText == NULL)
+ return FALSE;
+
+ if(!GetTextFace(lpszText, nLen))
+ return FALSE;
+
+ bstrFace = ::SysAllocString(T2OLE(lpszText));
+ return (bstrFace != NULL) ? TRUE : FALSE;
+ }
+#endif
+#endif // !_ATL_NO_COM
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetTextFace(_CSTRING_NS::CString& strFace) const
+ {
+ ATLASSERT(m_hDC != NULL);
+
+ int nLen = GetTextFaceLen();
+ if(nLen == 0)
+ return 0;
+
+ LPTSTR lpstr = strFace.GetBufferSetLength(nLen);
+ if(lpstr == NULL)
+ return 0;
+ int nRet = GetTextFace(lpstr, nLen);
+ strFace.ReleaseBuffer();
+ return nRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextMetrics(m_hDC, lpMetrics);
+ }
+
+#ifndef _WIN32_WCE
+ int SetTextJustification(int nBreakExtra, int nBreakCount)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetTextJustification(m_hDC, nBreakExtra, nBreakCount);
+ }
+
+ int GetTextCharacterExtra() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextCharacterExtra(m_hDC);
+ }
+
+ int SetTextCharacterExtra(int nCharExtra)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetTextCharacterExtra(m_hDC, nCharExtra);
+ }
+#endif // !_WIN32_WCE
+
+// Advanced Drawing
+ BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawEdge(m_hDC, lpRect, nEdge, nFlags);
+ }
+
+ BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawFrameControl(m_hDC, lpRect, nType, nState);
+ }
+
+// Scrolling Functions
+ BOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ScrollDC(m_hDC, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate);
+ }
+
+// Font Functions
+#ifndef _WIN32_WCE
+ BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharWidth(m_hDC, nFirstChar, nLastChar, lpBuffer);
+ }
+
+ // GetCharWidth32 is not supported under Win9x
+ BOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharWidth32(m_hDC, nFirstChar, nLastChar, lpBuffer);
+ }
+
+ DWORD SetMapperFlags(DWORD dwFlag)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetMapperFlags(m_hDC, dwFlag);
+ }
+
+ BOOL GetAspectRatioFilter(LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetAspectRatioFilterEx(m_hDC, lpSize);
+ }
+
+ BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharABCWidths(m_hDC, nFirstChar, nLastChar, lpabc);
+ }
+
+ DWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetFontData(m_hDC, dwTable, dwOffset, lpData, cbData);
+ }
+
+ int GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetKerningPairs(m_hDC, nPairs, lpkrnpair);
+ }
+
+ UINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetOutlineTextMetrics(m_hDC, cbData, lpotm);
+ }
+
+ DWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetGlyphOutline(m_hDC, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2);
+ }
+
+ BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharABCWidthsFloat(m_hDC, nFirstChar, nLastChar, lpABCF);
+ }
+
+ BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharWidthFloat(m_hDC, nFirstChar, nLastChar, lpFloatBuffer);
+ }
+#endif // !_WIN32_WCE
+
+// Printer/Device Escape Functions
+#ifndef _WIN32_WCE
+ int Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData);
+ }
+#endif // !_WIN32_WCE
+
+ int Escape(int nEscape, int nInputSize, LPCSTR lpszInputData,
+ int nOutputSize, LPSTR lpszOutputData)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ExtEscape(m_hDC, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData);
+ }
+
+#ifndef _WIN32_WCE
+ int DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DrawEscape(m_hDC, nEscape, nInputSize, lpszInputData);
+ }
+#endif // !_WIN32_WCE
+
+ // Escape helpers
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))
+ int StartDoc(LPCTSTR lpszDocName) // old Win3.0 version
+ {
+ DOCINFO di = { 0 };
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = lpszDocName;
+ return StartDoc(&di);
+ }
+
+ int StartDoc(LPDOCINFO lpDocInfo)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StartDoc(m_hDC, lpDocInfo);
+ }
+
+ int StartPage()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StartPage(m_hDC);
+ }
+
+ int EndPage()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::EndPage(m_hDC);
+ }
+
+ int SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int))
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetAbortProc(m_hDC, (ABORTPROC)lpfn);
+ }
+
+ int AbortDoc()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::AbortDoc(m_hDC);
+ }
+
+ int EndDoc()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::EndDoc(m_hDC);
+ }
+#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))
+
+// MetaFile Functions
+#ifndef _WIN32_WCE
+ BOOL PlayMetaFile(HMETAFILE hMF)
+ {
+ ATLASSERT(m_hDC != NULL);
+ if(::GetDeviceCaps(m_hDC, TECHNOLOGY) == DT_METAFILE)
+ {
+ // playing metafile in metafile, just use core windows API
+ return ::PlayMetaFile(m_hDC, hMF);
+ }
+
+ // for special playback, lParam == pDC
+ return ::EnumMetaFile(m_hDC, hMF, EnumMetaFileProc, (LPARAM)this);
+ }
+
+ BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::PlayEnhMetaFile(m_hDC, hEnhMetaFile, lpBounds);
+ }
+
+ BOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GdiComment(m_hDC, nDataSize, pCommentData);
+ }
+
+ // Special handling for metafile playback
+ static int CALLBACK EnumMetaFileProc(HDC hDC, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam)
+ {
+ CDCHandle* pDC = (CDCHandle*)lParam;
+
+ switch (pMetaRec->rdFunction)
+ {
+ case META_SETMAPMODE:
+ pDC->SetMapMode((int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SETWINDOWEXT:
+ pDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SETWINDOWORG:
+ pDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SETVIEWPORTEXT:
+ pDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SETVIEWPORTORG:
+ pDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SCALEWINDOWEXT:
+ pDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2],
+ (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SCALEVIEWPORTEXT:
+ pDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2],
+ (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_OFFSETVIEWPORTORG:
+ pDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SAVEDC:
+ pDC->SaveDC();
+ break;
+ case META_RESTOREDC:
+ pDC->RestoreDC((int)(short)pMetaRec->rdParm[0]);
+ break;
+ case META_SETBKCOLOR:
+ pDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);
+ break;
+ case META_SETTEXTCOLOR:
+ pDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);
+ break;
+
+ // need to watch out for SelectObject(HFONT), for custom font mapping
+ case META_SELECTOBJECT:
+ {
+ HGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]];
+ UINT nObjType = ::GetObjectType(hObject);
+ if(nObjType == 0)
+ {
+ // object type is unknown, determine if it is a font
+ HFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT);
+ HFONT hFontOld = (HFONT)::SelectObject(pDC->m_hDC, hStockFont);
+ HGDIOBJ hObjOld = ::SelectObject(pDC->m_hDC, hObject);
+ if(hObjOld == hStockFont)
+ {
+ // got the stock object back, so must be selecting a font
+ pDC->SelectFont((HFONT)hObject);
+ break; // don't play the default record
+ }
+ else
+ {
+ // didn't get the stock object back, so restore everything
+ ::SelectObject(pDC->m_hDC, hFontOld);
+ ::SelectObject(pDC->m_hDC, hObjOld);
+ }
+ // and fall through to PlayMetaFileRecord...
+ }
+ else if(nObjType == OBJ_FONT)
+ {
+ // play back as CDCHandle::SelectFont(HFONT)
+ pDC->SelectFont((HFONT)hObject);
+ break; // don't play the default record
+ }
+ }
+ // fall through...
+
+ default:
+ ::PlayMetaFileRecord(hDC, pHandleTable, pMetaRec, nHandles);
+ break;
+ }
+
+ return 1;
+ }
+#endif // !_WIN32_WCE
+
+// Path Functions
+#ifndef _WIN32_WCE
+ BOOL AbortPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::AbortPath(m_hDC);
+ }
+
+ BOOL BeginPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::BeginPath(m_hDC);
+ }
+
+ BOOL CloseFigure()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::CloseFigure(m_hDC);
+ }
+
+ BOOL EndPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::EndPath(m_hDC);
+ }
+
+ BOOL FillPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FillPath(m_hDC);
+ }
+
+ BOOL FlattenPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::FlattenPath(m_hDC);
+ }
+
+ BOOL StrokeAndFillPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StrokeAndFillPath(m_hDC);
+ }
+
+ BOOL StrokePath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StrokePath(m_hDC);
+ }
+
+ BOOL WidenPath()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::WidenPath(m_hDC);
+ }
+
+ BOOL GetMiterLimit(PFLOAT pfMiterLimit) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetMiterLimit(m_hDC, pfMiterLimit);
+ }
+
+ BOOL SetMiterLimit(float fMiterLimit)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetMiterLimit(m_hDC, fMiterLimit, NULL);
+ }
+
+ int GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetPath(m_hDC, lpPoints, lpTypes, nCount);
+ }
+
+ BOOL SelectClipPath(int nMode)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SelectClipPath(m_hDC, nMode);
+ }
+#endif // !_WIN32_WCE
+
+// Misc Helper Functions
+ static CBrushHandle PASCAL GetHalftoneBrush()
+ {
+ HBRUSH halftoneBrush = NULL;
+ WORD grayPattern[8];
+ for(int i = 0; i < 8; i++)
+ grayPattern[i] = (WORD)(0x5555 << (i & 1));
+ HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);
+ if(grayBitmap != NULL)
+ {
+ halftoneBrush = ::CreatePatternBrush(grayBitmap);
+ DeleteObject(grayBitmap);
+ }
+ return CBrushHandle(halftoneBrush);
+ }
+
+ void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL)
+ {
+ // first, determine the update region and select it
+ CRgn rgnOutside;
+ rgnOutside.CreateRectRgnIndirect(lpRect);
+ RECT rect = *lpRect;
+ ::InflateRect(&rect, -size.cx, -size.cy);
+ ::IntersectRect(&rect, &rect, lpRect);
+ CRgn rgnInside;
+ rgnInside.CreateRectRgnIndirect(&rect);
+ CRgn rgnNew;
+ rgnNew.CreateRectRgn(0, 0, 0, 0);
+ rgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR);
+
+ HBRUSH hBrushOld = NULL;
+ CBrush brushHalftone;
+ if(hBrush == NULL)
+ brushHalftone = hBrush = CDCHandle::GetHalftoneBrush();
+ if(hBrushLast == NULL)
+ hBrushLast = hBrush;
+
+ CRgn rgnLast;
+ CRgn rgnUpdate;
+ if(lpRectLast != NULL)
+ {
+ // find difference between new region and old region
+ rgnLast.CreateRectRgn(0, 0, 0, 0);
+ rgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom);
+ rect = *lpRectLast;
+ ::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy);
+ ::IntersectRect(&rect, &rect, lpRectLast);
+ rgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom);
+ rgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR);
+
+ // only diff them if brushes are the same
+ if(hBrush == hBrushLast)
+ {
+ rgnUpdate.CreateRectRgn(0, 0, 0, 0);
+ rgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR);
+ }
+ }
+ if(hBrush != hBrushLast && lpRectLast != NULL)
+ {
+ // brushes are different -- erase old region first
+ SelectClipRgn(rgnLast);
+ GetClipBox(&rect);
+ hBrushOld = SelectBrush(hBrushLast);
+ PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
+ SelectBrush(hBrushOld);
+ hBrushOld = NULL;
+ }
+
+ // draw into the update/new region
+ SelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate);
+ GetClipBox(&rect);
+ hBrushOld = SelectBrush(hBrush);
+ PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
+
+ // cleanup DC
+ if(hBrushOld != NULL)
+ SelectBrush(hBrushOld);
+ SelectClipRgn(NULL);
+ }
+
+ void FillSolidRect(LPCRECT lpRect, COLORREF clr)
+ {
+ ATLASSERT(m_hDC != NULL);
+
+ COLORREF clrOld = ::SetBkColor(m_hDC, clr);
+ ATLASSERT(clrOld != CLR_INVALID);
+ if(clrOld != CLR_INVALID)
+ {
+ ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);
+ ::SetBkColor(m_hDC, clrOld);
+ }
+ }
+
+ void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr)
+ {
+ ATLASSERT(m_hDC != NULL);
+
+ RECT rect = { x, y, x + cx, y + cy };
+ FillSolidRect(&rect, clr);
+ }
+
+ void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)
+ {
+ Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left,
+ lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);
+ }
+
+ void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight)
+ {
+ FillSolidRect(x, y, cx - 1, 1, clrTopLeft);
+ FillSolidRect(x, y, 1, cy - 1, clrTopLeft);
+ FillSolidRect(x + cx, y, -1, cy, clrBottomRight);
+ FillSolidRect(x, y + cy, cx, -1, clrBottomRight);
+ }
+
+// DIB support
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
+ int SetDIBitsToDevice(int x, int y, DWORD dwWidth, DWORD dwHeight, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetDIBitsToDevice(m_hDC, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+ int StretchDIBits(int x, int y, int nWidth, int nHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse, DWORD dwRop)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::StretchDIBits(m_hDC, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop);
+ }
+
+ UINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors);
+ }
+
+ UINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+
+// OpenGL support
+#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)
+ int ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ChoosePixelFormat(m_hDC, ppfd);
+ }
+
+ int DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::DescribePixelFormat(m_hDC, iPixelFormat, nBytes, ppfd);
+ }
+
+ int GetPixelFormat() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetPixelFormat(m_hDC);
+ }
+
+ BOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetPixelFormat(m_hDC, iPixelFormat, ppfd);
+ }
+
+ BOOL SwapBuffers()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SwapBuffers(m_hDC);
+ }
+
+ HGLRC wglCreateContext()
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglCreateContext(m_hDC);
+ }
+
+ HGLRC wglCreateLayerContext(int iLayerPlane)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglCreateLayerContext(m_hDC, iLayerPlane);
+ }
+
+ BOOL wglMakeCurrent(HGLRC hglrc)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglMakeCurrent(m_hDC, hglrc);
+ }
+
+ BOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglUseFontBitmaps(m_hDC, dwFirst, dwCount, listBase);
+ }
+
+ BOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglUseFontOutlines(m_hDC, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf);
+ }
+
+ BOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglDescribeLayerPlane(m_hDC, iPixelFormat, iLayerPlane, nBytes, plpd);
+ }
+
+ int wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglSetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr);
+ }
+
+ int wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglGetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr);
+ }
+
+ BOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglRealizeLayerPalette(m_hDC, iLayerPlane, bRealize);
+ }
+
+ BOOL wglSwapLayerBuffers(UINT uPlanes)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::wglSwapLayerBuffers(m_hDC, uPlanes);
+ }
+#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)
+
+// New for Windows 2000 only
+#if (_WIN32_WINNT >= 0x0500)
+ COLORREF GetDCPenColor() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetDCPenColor(m_hDC);
+ }
+
+ COLORREF SetDCPenColor(COLORREF clr)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetDCPenColor(m_hDC, clr);
+ }
+
+ COLORREF GetDCBrushColor() const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetDCBrushColor(m_hDC);
+ }
+
+ COLORREF SetDCBrushColor(COLORREF clr)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::SetDCBrushColor(m_hDC, clr);
+ }
+
+#ifndef _WIN32_WCE
+ DWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetFontUnicodeRanges(m_hDC, lpgs);
+ }
+#endif // !_WIN32_WCE
+
+ DWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetGlyphIndices(m_hDC, lpstr, cch, pgi, dwFlags);
+ }
+
+ BOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextExtentPointI(m_hDC, pgiIn, cgi, lpSize);
+ }
+
+ BOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetTextExtentExPointI(m_hDC, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize);
+ }
+
+ BOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharWidthI(m_hDC, giFirst, cgi, pgi, lpBuffer);
+ }
+
+ BOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::GetCharABCWidthsI(m_hDC, giFirst, cgi, pgi, lpabc);
+ }
+#endif // (_WIN32_WINNT >= 0x0500)
+
+// New for Windows 2000 and Windows 98
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ BOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries)
+ {
+ ATLASSERT(m_hDC != NULL);
+ return ::ColorCorrectPalette(m_hDC, hPalette, dwFirstEntry, dwNumOfEntries);
+ }
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+};
+
+typedef CDCT<false> CDCHandle;
+typedef CDCT<true> CDC;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDC Helpers
+
+class CPaintDC : public CDC
+{
+public:
+// Data members
+ HWND m_hWnd;
+ PAINTSTRUCT m_ps;
+
+// Constructor/destructor
+ CPaintDC(HWND hWnd)
+ {
+ ATLASSERT(::IsWindow(hWnd));
+ m_hWnd = hWnd;
+ m_hDC = ::BeginPaint(hWnd, &m_ps);
+ }
+
+ ~CPaintDC()
+ {
+ ATLASSERT(m_hDC != NULL);
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::EndPaint(m_hWnd, &m_ps);
+ Detach();
+ }
+};
+
+class CClientDC : public CDC
+{
+public:
+// Data members
+ HWND m_hWnd;
+
+// Constructor/destructor
+ CClientDC(HWND hWnd)
+ {
+ ATLASSERT(hWnd == NULL || ::IsWindow(hWnd));
+ m_hWnd = hWnd;
+ m_hDC = ::GetDC(hWnd);
+ }
+
+ ~CClientDC()
+ {
+ ATLASSERT(m_hDC != NULL);
+ ::ReleaseDC(m_hWnd, Detach());
+ }
+};
+
+class CWindowDC : public CDC
+{
+public:
+// Data members
+ HWND m_hWnd;
+
+// Constructor/destructor
+ CWindowDC(HWND hWnd)
+ {
+ ATLASSERT(hWnd == NULL || ::IsWindow(hWnd));
+ m_hWnd = hWnd;
+ m_hDC = ::GetWindowDC(hWnd);
+ }
+
+ ~CWindowDC()
+ {
+ ATLASSERT(m_hDC != NULL);
+ ::ReleaseDC(m_hWnd, Detach());
+ }
+};
+
+class CMemoryDC : public CDC
+{
+public:
+// Data members
+ HDC m_hDCOriginal;
+ RECT m_rcPaint;
+ CBitmap m_bmp;
+ HBITMAP m_hBmpOld;
+
+// Constructor/destructor
+ CMemoryDC(HDC hDC, RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL)
+ {
+ m_rcPaint = rcPaint;
+ CreateCompatibleDC(m_hDCOriginal);
+ ATLASSERT(m_hDC != NULL);
+ m_bmp.CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top);
+ ATLASSERT(m_bmp.m_hBitmap != NULL);
+ m_hBmpOld = SelectBitmap(m_bmp);
+ SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top);
+ }
+
+ ~CMemoryDC()
+ {
+ ::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY);
+ SelectBitmap(m_hBmpOld);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Enhanced metafile support
+
+#ifndef _WIN32_WCE
+
+class CEnhMetaFileInfo
+{
+public:
+// Data members
+ HENHMETAFILE m_hEMF;
+ BYTE* m_pBits;
+ TCHAR* m_pDesc;
+ ENHMETAHEADER m_header;
+ PIXELFORMATDESCRIPTOR m_pfd;
+
+// Constructor/destructor
+ CEnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), m_hEMF(hEMF)
+ { }
+
+ ~CEnhMetaFileInfo()
+ {
+ delete [] m_pBits;
+ delete [] m_pDesc;
+ }
+
+// Operations
+ BYTE* GetEnhMetaFileBits()
+ {
+ ATLASSERT(m_hEMF != NULL);
+ UINT nBytes = ::GetEnhMetaFileBits(m_hEMF, 0, NULL);
+ delete [] m_pBits;
+ m_pBits = NULL;
+ ATLTRY(m_pBits = new BYTE[nBytes]);
+ if (m_pBits != NULL)
+ ::GetEnhMetaFileBits(m_hEMF, nBytes, m_pBits);
+ return m_pBits;
+ }
+
+ LPTSTR GetEnhMetaFileDescription()
+ {
+ ATLASSERT(m_hEMF != NULL);
+ UINT nLen = ::GetEnhMetaFileDescription(m_hEMF, 0, NULL);
+ delete [] m_pDesc;
+ m_pDesc = NULL;
+ ATLTRY(m_pDesc = new TCHAR[nLen]);
+ if (m_pDesc != NULL)
+ nLen = ::GetEnhMetaFileDescription(m_hEMF, nLen, m_pDesc);
+ return m_pDesc;
+ }
+
+ ENHMETAHEADER* GetEnhMetaFileHeader()
+ {
+ ATLASSERT(m_hEMF != NULL);
+ memset(&m_header, 0, sizeof(m_header));
+ m_header.iType = EMR_HEADER;
+ m_header.nSize = sizeof(ENHMETAHEADER);
+ UINT n = ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), &m_header);
+ return (n != 0) ? &m_header : NULL;
+ }
+
+ PIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat()
+ {
+ ATLASSERT(m_hEMF != NULL);
+ memset(&m_pfd, 0, sizeof(m_pfd));
+ UINT n = ::GetEnhMetaFilePixelFormat(m_hEMF, sizeof(m_pfd), &m_pfd);
+ return (n != 0) ? &m_pfd : NULL;
+ }
+};
+
+
+template <bool t_bManaged>
+class CEnhMetaFileT
+{
+public:
+// Data members
+ HENHMETAFILE m_hEMF;
+
+// Constructor/destructor
+ CEnhMetaFileT(HENHMETAFILE hEMF = NULL) : m_hEMF(hEMF)
+ {
+ }
+
+ ~CEnhMetaFileT()
+ {
+ if(t_bManaged && m_hEMF != NULL)
+ DeleteObject();
+ }
+
+// Operations
+ CEnhMetaFileT<t_bManaged>& operator =(HENHMETAFILE hEMF)
+ {
+ Attach(hEMF);
+ return *this;
+ }
+
+ void Attach(HENHMETAFILE hEMF)
+ {
+ if(t_bManaged && m_hEMF != NULL && m_hEMF != hEMF)
+ DeleteObject();
+ m_hEMF = hEMF;
+ }
+
+ HENHMETAFILE Detach()
+ {
+ HENHMETAFILE hEMF = m_hEMF;
+ m_hEMF = NULL;
+ return hEMF;
+ }
+
+ operator HENHMETAFILE() const { return m_hEMF; }
+
+ bool IsNull() const { return (m_hEMF == NULL); }
+
+ BOOL DeleteObject()
+ {
+ ATLASSERT(m_hEMF != NULL);
+ BOOL bRet = ::DeleteEnhMetaFile(m_hEMF);
+ m_hEMF = NULL;
+ return bRet;
+ }
+
+ UINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const
+ {
+ ATLASSERT(m_hEMF != NULL);
+ return ::GetEnhMetaFileBits(m_hEMF, cbBuffer, lpbBuffer);
+ }
+
+ UINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const
+ {
+ ATLASSERT(m_hEMF != NULL);
+ return ::GetEnhMetaFileDescription(m_hEMF, cchBuffer, lpszDescription);
+ }
+
+ UINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const
+ {
+ ATLASSERT(m_hEMF != NULL);
+ lpemh->iType = EMR_HEADER;
+ lpemh->nSize = sizeof(ENHMETAHEADER);
+ return ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), lpemh);
+ }
+
+ UINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const
+ {
+ ATLASSERT(m_hEMF != NULL);
+ return ::GetEnhMetaFilePaletteEntries(m_hEMF, cEntries, lppe);
+ }
+
+ UINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const
+ {
+ ATLASSERT(m_hEMF != NULL);
+ return ::GetEnhMetaFilePixelFormat(m_hEMF, cbBuffer, ppfd);
+ }
+};
+
+typedef CEnhMetaFileT<false> CEnhMetaFileHandle;
+typedef CEnhMetaFileT<true> CEnhMetaFile;
+
+
+class CEnhMetaFileDC : public CDC
+{
+public:
+// Constructor/destructor
+ CEnhMetaFileDC()
+ {
+ }
+
+ CEnhMetaFileDC(HDC hdc, LPCRECT lpRect)
+ {
+ Create(hdc, NULL, lpRect, NULL);
+ ATLASSERT(m_hDC != NULL);
+ }
+
+ CEnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)
+ {
+ Create(hdcRef, lpFilename, lpRect, lpDescription);
+ ATLASSERT(m_hDC != NULL);
+ }
+
+ ~CEnhMetaFileDC()
+ {
+ HENHMETAFILE hEMF = Close();
+ if (hEMF != NULL)
+ ::DeleteEnhMetaFile(hEMF);
+ }
+
+// Operations
+ void Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)
+ {
+ ATLASSERT(m_hDC == NULL);
+ m_hDC = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription);
+ }
+
+ HENHMETAFILE Close()
+ {
+ HENHMETAFILE hEMF = NULL;
+ if (m_hDC != NULL)
+ {
+ hEMF = ::CloseEnhMetaFile(m_hDC);
+ m_hDC = NULL;
+ }
+ return hEMF;
+ }
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// WinCE compatible clipboard CF_DIB format support functions
+
+#ifndef _WTL_NO_DIB16
+
+#define DIBINFO16_BITFIELDS { 31744, 992, 31 }
+
+// DIBINFO16 - To avoid color table problems in WinCE we only create this type of Dib
+struct DIBINFO16 // a BITMAPINFO with 2 additional color bitfields
+{
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[3];
+
+ DIBINFO16(SIZE size)
+ {
+ BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), size.cx, size.cy,
+ 1, 16, BI_BITFIELDS, 2 * size.cx * size.cy , 0, 0, 3 };
+ DWORD dw[3] = DIBINFO16_BITFIELDS ;
+
+ bmiHeader = bmih;
+ SecureHelper::memcpy_x(bmiColors, sizeof(bmiColors), dw, 3 * sizeof(DWORD));
+ }
+};
+
+
+// AtlxxxDibxxx minimal packed DIB implementation and helpers to copy and paste CF_DIB
+
+inline bool AtlIsDib16(LPBITMAPINFOHEADER pbmih)
+{
+ return (pbmih->biBitCount == 16) && (pbmih->biCompression == BI_BITFIELDS);
+}
+
+inline int AtlGetDibColorTableSize(LPBITMAPINFOHEADER pbmih)
+{
+ switch (pbmih->biBitCount)
+ {
+ case 2:
+ case 4:
+ case 8:
+ return pbmih->biClrUsed ? pbmih->biClrUsed : 1 << pbmih->biBitCount;
+ case 24:
+ break;
+ case 16:
+ case 32:
+ return pbmih->biCompression == BI_BITFIELDS ? 3 : 0;
+ default:
+ ATLASSERT(FALSE); // should never come here
+ }
+
+ return 0;
+}
+
+inline int AtlGetDibNumColors(LPBITMAPINFOHEADER pbmih)
+{
+ switch (pbmih->biBitCount)
+ {
+ case 2:
+ case 4:
+ case 8:
+ if (pbmih->biClrUsed)
+ return pbmih->biClrUsed;
+ else
+ break;
+ case 16:
+ if (pbmih->biCompression == BI_BITFIELDS )
+ return 1 << 15;
+ else
+ break;
+ case 24:
+ break;
+ case 32:
+ if (pbmih->biCompression == BI_BITFIELDS )
+ return 1 << 24;
+ else
+ break;
+ default:
+ ATLASSERT(FALSE);
+ }
+
+ return 1 << pbmih->biBitCount;
+}
+
+inline HBITMAP AtlGetDibBitmap(LPBITMAPINFO pbmi)
+{
+ CDC dc(NULL);
+ void* pBits = NULL;
+
+ LPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD);
+ HBITMAP hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL);
+ if (hbm != NULL)
+ {
+ int cbBits = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biHeight * pbmi->bmiHeader.biBitCount / 8;
+ SecureHelper::memcpy_x(pBits, cbBits, pDibBits, pbmi->bmiHeader.biSizeImage);
+ }
+
+ return hbm;
+}
+
+inline HBITMAP AtlCopyBitmap(HBITMAP hbm, SIZE sizeDst, bool bAsBitmap = false)
+{
+ CDC hdcSrc = CreateCompatibleDC(NULL);
+ CDC hdcDst = CreateCompatibleDC(NULL);
+
+ CBitmapHandle hbmOld = NULL, hbmOld2 = NULL, bmSrc = hbm;
+
+ CBitmap bmNew = NULL;
+
+ SIZE sizeSrc = { 0 };
+ bmSrc.GetSize(sizeSrc);
+
+ hbmOld = hdcSrc.SelectBitmap(bmSrc);
+
+ if (bAsBitmap)
+ {
+ bmNew.CreateCompatibleBitmap(hdcSrc, sizeDst.cx, sizeDst.cy);
+ }
+ else
+ {
+ DIBINFO16 dib16(sizeDst);
+ LPVOID pBits = NULL;
+ bmNew = CreateDIBSection(hdcDst, (const BITMAPINFO*)&dib16, DIB_RGB_COLORS, &pBits, NULL, NULL);
+ }
+
+ ATLASSERT(!bmNew.IsNull());
+
+ hbmOld2 = hdcDst.SelectBitmap(bmNew);
+ BOOL bOK = FALSE;
+
+ if ((sizeDst.cx == sizeSrc.cx) && (sizeDst.cy == sizeSrc.cy))
+ bOK = hdcDst.BitBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, SRCCOPY);
+ else
+ bOK = hdcDst.StretchBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, sizeSrc.cx, sizeSrc.cy, SRCCOPY);
+
+ hdcSrc.SelectBitmap(hbmOld);
+ hdcDst.SelectBitmap(hbmOld2);
+
+ if (bOK == FALSE)
+ bmNew.DeleteObject();
+
+ return bmNew.Detach();
+}
+
+inline HLOCAL AtlCreatePackedDib16(HBITMAP hbm, SIZE size)
+{
+ DIBSECTION ds = { 0 };
+ LPBYTE pDib = NULL;
+ bool bCopied = false;
+
+ bool bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds);
+ if ((bOK == FALSE) || (ds.dsBm.bmBits == NULL) || (AtlIsDib16(&ds.dsBmih) == FALSE) ||
+ (ds.dsBmih.biWidth != size.cx ) || (ds.dsBmih.biHeight != size.cy ))
+ {
+ if ((hbm = AtlCopyBitmap(hbm, size)) != NULL)
+ {
+ bCopied = true;
+ bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds);
+ }
+ else
+ {
+ bOK = FALSE;
+ }
+ }
+
+ if((bOK != FALSE) && (AtlIsDib16(&ds.dsBmih) != FALSE) && (ds.dsBm.bmBits != NULL))
+ {
+ pDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage);
+ if (pDib != NULL)
+ {
+ SecureHelper::memcpy_x(pDib, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage, &ds.dsBmih, sizeof(DIBINFO16));
+ SecureHelper::memcpy_x(pDib + sizeof(DIBINFO16), ds.dsBmih.biSizeImage, ds.dsBm.bmBits, ds.dsBmih.biSizeImage);
+ }
+ }
+
+ if (bCopied == true)
+ DeleteObject(hbm);
+
+ return (HLOCAL)pDib;
+}
+
+inline bool AtlSetClipboardDib16(HBITMAP hbm, SIZE size, HWND hWnd)
+{
+ ATLASSERT(::IsWindow(hWnd));
+ BOOL bOK = OpenClipboard(hWnd);
+ if (bOK != FALSE)
+ {
+ bOK = EmptyClipboard();
+ if (bOK != FALSE)
+ {
+ HLOCAL hDib = AtlCreatePackedDib16(hbm, size);
+ if (hDib != NULL)
+ {
+ bOK = SetClipboardData(CF_DIB, hDib) != NULL;
+ if (bOK == FALSE)
+ LocalFree(hDib);
+ }
+ else
+ {
+ bOK = FALSE;
+ }
+ }
+ CloseClipboard();
+ }
+
+ return (bOK != FALSE);
+}
+
+inline HBITMAP AtlGetClipboardDib(HWND hWnd)
+{
+ ATLASSERT(::IsWindow(hWnd) != FALSE);
+ HBITMAP hbm = NULL;
+ if (OpenClipboard(hWnd) != FALSE)
+ {
+ LPBITMAPINFO pbmi = (LPBITMAPINFO)GetClipboardData(CF_DIB);
+ if (pbmi != NULL)
+ hbm = AtlGetDibBitmap(pbmi);
+ CloseClipboard();
+ }
+
+ return hbm;
+}
+
+#endif // _WTL_NO_DIB16
+
+}; // namespace WTL
+
+#endif // __ATLGDI_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLMISC_H__
+#define __ATLMISC_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlmisc.h requires atlapp.h to be included first
+#endif
+
+
+#ifdef _ATL_TMP_NO_CSTRING
+ #define _WTL_NO_CSTRING
+#endif
+
+#if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
+ #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined
+#endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
+
+#if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)
+ #define _WTL_USE_CSTRING
+#endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)
+
+#ifndef _WTL_NO_CSTRING
+ #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
+ #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined
+ #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
+#endif // !_WTL_NO_CSTRING
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CSize
+// CPoint
+// CRect
+// CString
+//
+// CRecentDocumentListBase<T, t_cchItemLen, t_nFirstID, t_nLastID>
+// CRecentDocumentList
+// CFindFile
+//
+// Global functions:
+// AtlGetStockPen()
+// AtlGetStockBrush()
+// AtlGetStockFont()
+// AtlGetStockPalette()
+//
+// AtlCompactPath()
+
+
+namespace WTL
+{
+
+#ifndef _WTL_NO_WTYPES
+
+// forward declarations
+class CSize;
+class CPoint;
+class CRect;
+
+///////////////////////////////////////////////////////////////////////////////
+// CSize - Wrapper for Windows SIZE structure.
+
+class CSize : public SIZE
+{
+public:
+// Constructors
+ CSize()
+ {
+ cx = 0;
+ cy = 0;
+ }
+
+ CSize(int initCX, int initCY)
+ {
+ cx = initCX;
+ cy = initCY;
+ }
+
+ CSize(SIZE initSize)
+ {
+ *(SIZE*)this = initSize;
+ }
+
+ CSize(POINT initPt)
+ {
+ *(POINT*)this = initPt;
+ }
+
+ CSize(DWORD dwSize)
+ {
+ cx = (short)LOWORD(dwSize);
+ cy = (short)HIWORD(dwSize);
+ }
+
+// Operations
+ BOOL operator ==(SIZE size) const
+ {
+ return (cx == size.cx && cy == size.cy);
+ }
+
+ BOOL operator !=(SIZE size) const
+ {
+ return (cx != size.cx || cy != size.cy);
+ }
+
+ void operator +=(SIZE size)
+ {
+ cx += size.cx;
+ cy += size.cy;
+ }
+
+ void operator -=(SIZE size)
+ {
+ cx -= size.cx;
+ cy -= size.cy;
+ }
+
+ void SetSize(int CX, int CY)
+ {
+ cx = CX;
+ cy = CY;
+ }
+
+// Operators returning CSize values
+ CSize operator +(SIZE size) const
+ {
+ return CSize(cx + size.cx, cy + size.cy);
+ }
+
+ CSize operator -(SIZE size) const
+ {
+ return CSize(cx - size.cx, cy - size.cy);
+ }
+
+ CSize operator -() const
+ {
+ return CSize(-cx, -cy);
+ }
+
+// Operators returning CPoint values
+ CPoint operator +(POINT point) const;
+ CPoint operator -(POINT point) const;
+
+// Operators returning CRect values
+ CRect operator +(const RECT* lpRect) const;
+ CRect operator -(const RECT* lpRect) const;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPoint - Wrapper for Windows POINT structure.
+
+class CPoint : public POINT
+{
+public:
+// Constructors
+ CPoint()
+ {
+ x = 0;
+ y = 0;
+ }
+
+ CPoint(int initX, int initY)
+ {
+ x = initX;
+ y = initY;
+ }
+
+ CPoint(POINT initPt)
+ {
+ *(POINT*)this = initPt;
+ }
+
+ CPoint(SIZE initSize)
+ {
+ *(SIZE*)this = initSize;
+ }
+
+ CPoint(DWORD dwPoint)
+ {
+ x = (short)LOWORD(dwPoint);
+ y = (short)HIWORD(dwPoint);
+ }
+
+// Operations
+ void Offset(int xOffset, int yOffset)
+ {
+ x += xOffset;
+ y += yOffset;
+ }
+
+ void Offset(POINT point)
+ {
+ x += point.x;
+ y += point.y;
+ }
+
+ void Offset(SIZE size)
+ {
+ x += size.cx;
+ y += size.cy;
+ }
+
+ BOOL operator ==(POINT point) const
+ {
+ return (x == point.x && y == point.y);
+ }
+
+ BOOL operator !=(POINT point) const
+ {
+ return (x != point.x || y != point.y);
+ }
+
+ void operator +=(SIZE size)
+ {
+ x += size.cx;
+ y += size.cy;
+ }
+
+ void operator -=(SIZE size)
+ {
+ x -= size.cx;
+ y -= size.cy;
+ }
+
+ void operator +=(POINT point)
+ {
+ x += point.x;
+ y += point.y;
+ }
+
+ void operator -=(POINT point)
+ {
+ x -= point.x;
+ y -= point.y;
+ }
+
+ void SetPoint(int X, int Y)
+ {
+ x = X;
+ y = Y;
+ }
+
+// Operators returning CPoint values
+ CPoint operator +(SIZE size) const
+ {
+ return CPoint(x + size.cx, y + size.cy);
+ }
+
+ CPoint operator -(SIZE size) const
+ {
+ return CPoint(x - size.cx, y - size.cy);
+ }
+
+ CPoint operator -() const
+ {
+ return CPoint(-x, -y);
+ }
+
+ CPoint operator +(POINT point) const
+ {
+ return CPoint(x + point.x, y + point.y);
+ }
+
+// Operators returning CSize values
+ CSize operator -(POINT point) const
+ {
+ return CSize(x - point.x, y - point.y);
+ }
+
+// Operators returning CRect values
+ CRect operator +(const RECT* lpRect) const;
+ CRect operator -(const RECT* lpRect) const;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRect - Wrapper for Windows RECT structure.
+
+class CRect : public RECT
+{
+public:
+// Constructors
+ CRect()
+ {
+ left = 0;
+ top = 0;
+ right = 0;
+ bottom = 0;
+ }
+
+ CRect(int l, int t, int r, int b)
+ {
+ left = l;
+ top = t;
+ right = r;
+ bottom = b;
+ }
+
+ CRect(const RECT& srcRect)
+ {
+ ::CopyRect(this, &srcRect);
+ }
+
+ CRect(LPCRECT lpSrcRect)
+ {
+ ::CopyRect(this, lpSrcRect);
+ }
+
+ CRect(POINT point, SIZE size)
+ {
+ right = (left = point.x) + size.cx;
+ bottom = (top = point.y) + size.cy;
+ }
+
+ CRect(POINT topLeft, POINT bottomRight)
+ {
+ left = topLeft.x;
+ top = topLeft.y;
+ right = bottomRight.x;
+ bottom = bottomRight.y;
+ }
+
+// Attributes (in addition to RECT members)
+ int Width() const
+ {
+ return right - left;
+ }
+
+ int Height() const
+ {
+ return bottom - top;
+ }
+
+ CSize Size() const
+ {
+ return CSize(right - left, bottom - top);
+ }
+
+ CPoint& TopLeft()
+ {
+ return *((CPoint*)this);
+ }
+
+ CPoint& BottomRight()
+ {
+ return *((CPoint*)this + 1);
+ }
+
+ const CPoint& TopLeft() const
+ {
+ return *((CPoint*)this);
+ }
+
+ const CPoint& BottomRight() const
+ {
+ return *((CPoint*)this + 1);
+ }
+
+ CPoint CenterPoint() const
+ {
+ return CPoint((left + right) / 2, (top + bottom) / 2);
+ }
+
+ // convert between CRect and LPRECT/LPCRECT (no need for &)
+ operator LPRECT()
+ {
+ return this;
+ }
+
+ operator LPCRECT() const
+ {
+ return this;
+ }
+
+ BOOL IsRectEmpty() const
+ {
+ return ::IsRectEmpty(this);
+ }
+
+ BOOL IsRectNull() const
+ {
+ return (left == 0 && right == 0 && top == 0 && bottom == 0);
+ }
+
+ BOOL PtInRect(POINT point) const
+ {
+ return ::PtInRect(this, point);
+ }
+
+// Operations
+ void SetRect(int x1, int y1, int x2, int y2)
+ {
+ ::SetRect(this, x1, y1, x2, y2);
+ }
+
+ void SetRect(POINT topLeft, POINT bottomRight)
+ {
+ ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
+ }
+
+ void SetRectEmpty()
+ {
+ ::SetRectEmpty(this);
+ }
+
+ void CopyRect(LPCRECT lpSrcRect)
+ {
+ ::CopyRect(this, lpSrcRect);
+ }
+
+ BOOL EqualRect(LPCRECT lpRect) const
+ {
+ return ::EqualRect(this, lpRect);
+ }
+
+ void InflateRect(int x, int y)
+ {
+ ::InflateRect(this, x, y);
+ }
+
+ void InflateRect(SIZE size)
+ {
+ ::InflateRect(this, size.cx, size.cy);
+ }
+
+ void InflateRect(LPCRECT lpRect)
+ {
+ left -= lpRect->left;
+ top -= lpRect->top;
+ right += lpRect->right;
+ bottom += lpRect->bottom;
+ }
+
+ void InflateRect(int l, int t, int r, int b)
+ {
+ left -= l;
+ top -= t;
+ right += r;
+ bottom += b;
+ }
+
+ void DeflateRect(int x, int y)
+ {
+ ::InflateRect(this, -x, -y);
+ }
+
+ void DeflateRect(SIZE size)
+ {
+ ::InflateRect(this, -size.cx, -size.cy);
+ }
+
+ void DeflateRect(LPCRECT lpRect)
+ {
+ left += lpRect->left;
+ top += lpRect->top;
+ right -= lpRect->right;
+ bottom -= lpRect->bottom;
+ }
+
+ void DeflateRect(int l, int t, int r, int b)
+ {
+ left += l;
+ top += t;
+ right -= r;
+ bottom -= b;
+ }
+
+ void OffsetRect(int x, int y)
+ {
+ ::OffsetRect(this, x, y);
+ }
+ void OffsetRect(SIZE size)
+ {
+ ::OffsetRect(this, size.cx, size.cy);
+ }
+
+ void OffsetRect(POINT point)
+ {
+ ::OffsetRect(this, point.x, point.y);
+ }
+
+ void NormalizeRect()
+ {
+ int nTemp;
+ if (left > right)
+ {
+ nTemp = left;
+ left = right;
+ right = nTemp;
+ }
+ if (top > bottom)
+ {
+ nTemp = top;
+ top = bottom;
+ bottom = nTemp;
+ }
+ }
+
+ // absolute position of rectangle
+ void MoveToY(int y)
+ {
+ bottom = Height() + y;
+ top = y;
+ }
+
+ void MoveToX(int x)
+ {
+ right = Width() + x;
+ left = x;
+ }
+
+ void MoveToXY(int x, int y)
+ {
+ MoveToX(x);
+ MoveToY(y);
+ }
+
+ void MoveToXY(POINT pt)
+ {
+ MoveToX(pt.x);
+ MoveToY(pt.y);
+ }
+
+ // operations that fill '*this' with result
+ BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2)
+ {
+ return ::IntersectRect(this, lpRect1, lpRect2);
+ }
+
+ BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2)
+ {
+ return ::UnionRect(this, lpRect1, lpRect2);
+ }
+
+ BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2)
+ {
+ return ::SubtractRect(this, lpRectSrc1, lpRectSrc2);
+ }
+
+// Additional Operations
+ void operator =(const RECT& srcRect)
+ {
+ ::CopyRect(this, &srcRect);
+ }
+
+ BOOL operator ==(const RECT& rect) const
+ {
+ return ::EqualRect(this, &rect);
+ }
+
+ BOOL operator !=(const RECT& rect) const
+ {
+ return !::EqualRect(this, &rect);
+ }
+
+ void operator +=(POINT point)
+ {
+ ::OffsetRect(this, point.x, point.y);
+ }
+
+ void operator +=(SIZE size)
+ {
+ ::OffsetRect(this, size.cx, size.cy);
+ }
+
+ void operator +=(LPCRECT lpRect)
+ {
+ InflateRect(lpRect);
+ }
+
+ void operator -=(POINT point)
+ {
+ ::OffsetRect(this, -point.x, -point.y);
+ }
+
+ void operator -=(SIZE size)
+ {
+ ::OffsetRect(this, -size.cx, -size.cy);
+ }
+
+ void operator -=(LPCRECT lpRect)
+ {
+ DeflateRect(lpRect);
+ }
+
+ void operator &=(const RECT& rect)
+ {
+ ::IntersectRect(this, this, &rect);
+ }
+
+ void operator |=(const RECT& rect)
+ {
+ ::UnionRect(this, this, &rect);
+ }
+
+// Operators returning CRect values
+ CRect operator +(POINT pt) const
+ {
+ CRect rect(*this);
+ ::OffsetRect(&rect, pt.x, pt.y);
+ return rect;
+ }
+
+ CRect operator -(POINT pt) const
+ {
+ CRect rect(*this);
+ ::OffsetRect(&rect, -pt.x, -pt.y);
+ return rect;
+ }
+
+ CRect operator +(LPCRECT lpRect) const
+ {
+ CRect rect(this);
+ rect.InflateRect(lpRect);
+ return rect;
+ }
+
+ CRect operator +(SIZE size) const
+ {
+ CRect rect(*this);
+ ::OffsetRect(&rect, size.cx, size.cy);
+ return rect;
+ }
+
+ CRect operator -(SIZE size) const
+ {
+ CRect rect(*this);
+ ::OffsetRect(&rect, -size.cx, -size.cy);
+ return rect;
+ }
+
+ CRect operator -(LPCRECT lpRect) const
+ {
+ CRect rect(this);
+ rect.DeflateRect(lpRect);
+ return rect;
+ }
+
+ CRect operator &(const RECT& rect2) const
+ {
+ CRect rect;
+ ::IntersectRect(&rect, this, &rect2);
+ return rect;
+ }
+
+ CRect operator |(const RECT& rect2) const
+ {
+ CRect rect;
+ ::UnionRect(&rect, this, &rect2);
+ return rect;
+ }
+
+ CRect MulDiv(int nMultiplier, int nDivisor) const
+ {
+ return CRect(
+ ::MulDiv(left, nMultiplier, nDivisor),
+ ::MulDiv(top, nMultiplier, nDivisor),
+ ::MulDiv(right, nMultiplier, nDivisor),
+ ::MulDiv(bottom, nMultiplier, nDivisor));
+ }
+};
+
+
+// CSize implementation
+
+inline CPoint CSize::operator +(POINT point) const
+{ return CPoint(cx + point.x, cy + point.y); }
+
+inline CPoint CSize::operator -(POINT point) const
+{ return CPoint(cx - point.x, cy - point.y); }
+
+inline CRect CSize::operator +(const RECT* lpRect) const
+{ return CRect(lpRect) + *this; }
+
+inline CRect CSize::operator -(const RECT* lpRect) const
+{ return CRect(lpRect) - *this; }
+
+
+// CPoint implementation
+
+inline CRect CPoint::operator +(const RECT* lpRect) const
+{ return CRect(lpRect) + *this; }
+
+inline CRect CPoint::operator -(const RECT* lpRect) const
+{ return CRect(lpRect) - *this; }
+
+#endif // !_WTL_NO_WTYPES
+
+
+// WTL::CSize or ATL::CSize scalar operators
+
+#if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))
+
+template <class Num>
+inline CSize operator *(SIZE s, Num n)
+{
+ return CSize((int)(s.cx * n), (int)(s.cy * n));
+};
+
+template <class Num>
+inline void operator *=(SIZE & s, Num n)
+{
+ s = s * n;
+};
+
+template <class Num>
+inline CSize operator /(SIZE s, Num n)
+{
+ return CSize((int)(s.cx / n), (int)(s.cy / n));
+};
+
+template <class Num>
+inline void operator /=(SIZE & s, Num n)
+{
+ s = s / n;
+};
+
+#endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CString - String class
+
+#ifndef _WTL_NO_CSTRING
+
+struct CStringData
+{
+ long nRefs; // reference count
+ int nDataLength;
+ int nAllocLength;
+ // TCHAR data[nAllocLength]
+
+ TCHAR* data()
+ { return (TCHAR*)(this + 1); }
+};
+
+// Globals
+
+// For an empty string, m_pchData will point here
+// (note: avoids special case of checking for NULL m_pchData)
+// empty string data (and locked)
+_declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 };
+_declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData;
+_declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData));
+
+
+class CString
+{
+public:
+// Constructors
+ CString()
+ {
+ Init();
+ }
+
+ CString(const CString& stringSrc)
+ {
+ ATLASSERT(stringSrc.GetData()->nRefs != 0);
+ if (stringSrc.GetData()->nRefs >= 0)
+ {
+ ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
+ m_pchData = stringSrc.m_pchData;
+ InterlockedIncrement(&GetData()->nRefs);
+ }
+ else
+ {
+ Init();
+ *this = stringSrc.m_pchData;
+ }
+ }
+
+ CString(TCHAR ch, int nRepeat = 1)
+ {
+ ATLASSERT(!_istlead(ch)); // can't create a lead byte string
+ Init();
+ if (nRepeat >= 1)
+ {
+ if(AllocBuffer(nRepeat))
+ {
+#ifdef _UNICODE
+ for (int i = 0; i < nRepeat; i++)
+ m_pchData[i] = ch;
+#else
+ memset(m_pchData, ch, nRepeat);
+#endif
+ }
+ }
+ }
+
+ CString(LPCTSTR lpsz)
+ {
+ Init();
+ if (lpsz != NULL && HIWORD(lpsz) == NULL)
+ {
+ UINT nID = LOWORD((DWORD_PTR)lpsz);
+ if (!LoadString(nID))
+ ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID);
+ }
+ else
+ {
+ int nLen = SafeStrlen(lpsz);
+ if (nLen != 0)
+ {
+ if(AllocBuffer(nLen))
+ SecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR));
+ }
+ }
+ }
+
+#ifdef _UNICODE
+ CString(LPCSTR lpsz)
+ {
+ Init();
+#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
+ int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;
+#else
+ int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;
+#endif
+ if (nSrcLen != 0)
+ {
+ if(AllocBuffer(nSrcLen))
+ {
+ _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
+ ReleaseBuffer();
+ }
+ }
+ }
+#else // !_UNICODE
+ CString(LPCWSTR lpsz)
+ {
+ Init();
+ int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;
+ if (nSrcLen != 0)
+ {
+ if(AllocBuffer(nSrcLen * 2))
+ {
+ _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
+ ReleaseBuffer();
+ }
+ }
+ }
+#endif // !_UNICODE
+
+ CString(LPCTSTR lpch, int nLength)
+ {
+ Init();
+ if (nLength != 0)
+ {
+ if(AllocBuffer(nLength))
+ SecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR));
+ }
+ }
+
+#ifdef _UNICODE
+ CString(LPCSTR lpsz, int nLength)
+ {
+ Init();
+ if (nLength != 0)
+ {
+ if(AllocBuffer(nLength))
+ {
+ int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength + 1);
+ ReleaseBuffer((n >= 0) ? n : -1);
+ }
+ }
+ }
+#else // !_UNICODE
+ CString(LPCWSTR lpsz, int nLength)
+ {
+ Init();
+ if (nLength != 0)
+ {
+ if(((nLength * 2) > nLength) && AllocBuffer(nLength * 2))
+ {
+ int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, (nLength * 2) + 1, NULL, NULL);
+ ReleaseBuffer((n >= 0) ? n : -1);
+ }
+ }
+ }
+#endif // !_UNICODE
+
+ CString(const unsigned char* lpsz)
+ {
+ Init();
+ *this = (LPCSTR)lpsz;
+ }
+
+// Attributes & Operations
+ int GetLength() const // as an array of characters
+ {
+ return GetData()->nDataLength;
+ }
+
+ BOOL IsEmpty() const
+ {
+ return GetData()->nDataLength == 0;
+ }
+
+ void Empty() // free up the data
+ {
+ if (GetData()->nDataLength == 0)
+ return;
+
+ if (GetData()->nRefs >= 0)
+ Release();
+ else
+ *this = _T("");
+
+ ATLASSERT(GetData()->nDataLength == 0);
+ ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
+ }
+
+ TCHAR GetAt(int nIndex) const // 0 based
+ {
+ ATLASSERT(nIndex >= 0);
+ ATLASSERT(nIndex < GetData()->nDataLength);
+ return m_pchData[nIndex];
+ }
+
+ TCHAR operator [](int nIndex) const // same as GetAt
+ {
+ // same as GetAt
+ ATLASSERT(nIndex >= 0);
+ ATLASSERT(nIndex < GetData()->nDataLength);
+ return m_pchData[nIndex];
+ }
+
+ void SetAt(int nIndex, TCHAR ch)
+ {
+ ATLASSERT(nIndex >= 0);
+ ATLASSERT(nIndex < GetData()->nDataLength);
+
+ CopyBeforeWrite();
+ m_pchData[nIndex] = ch;
+ }
+
+ operator LPCTSTR() const // as a C string
+ {
+ return m_pchData;
+ }
+
+ // overloaded assignment
+ CString& operator =(const CString& stringSrc)
+ {
+ if (m_pchData != stringSrc.m_pchData)
+ {
+ if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0)
+ {
+ // actual copy necessary since one of the strings is locked
+ AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
+ }
+ else
+ {
+ // can just copy references around
+ Release();
+ ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
+ m_pchData = stringSrc.m_pchData;
+ InterlockedIncrement(&GetData()->nRefs);
+ }
+ }
+ return *this;
+ }
+
+ CString& operator =(TCHAR ch)
+ {
+ ATLASSERT(!_istlead(ch)); // can't set single lead byte
+ AssignCopy(1, &ch);
+ return *this;
+ }
+
+#ifdef _UNICODE
+ CString& operator =(char ch)
+ {
+ *this = (TCHAR)ch;
+ return *this;
+ }
+#endif
+
+ CString& operator =(LPCTSTR lpsz)
+ {
+ ATLASSERT(lpsz == NULL || _IsValidString(lpsz));
+ AssignCopy(SafeStrlen(lpsz), lpsz);
+ return *this;
+ }
+
+#ifdef _UNICODE
+ CString& operator =(LPCSTR lpsz)
+ {
+#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
+ int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;
+#else
+ int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;
+#endif
+ if(AllocBeforeWrite(nSrcLen))
+ {
+ _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
+ ReleaseBuffer();
+ }
+ return *this;
+ }
+#else // !_UNICODE
+ CString& operator =(LPCWSTR lpsz)
+ {
+ int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;
+ if(AllocBeforeWrite(nSrcLen * 2))
+ {
+ _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
+ ReleaseBuffer();
+ }
+ return *this;
+ }
+#endif // !_UNICODE
+
+ CString& operator =(const unsigned char* lpsz)
+ {
+ *this = (LPCSTR)lpsz;
+ return *this;
+ }
+
+ // string concatenation
+ CString& operator +=(const CString& string)
+ {
+ ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
+ return *this;
+ }
+
+ CString& operator +=(TCHAR ch)
+ {
+ ConcatInPlace(1, &ch);
+ return *this;
+ }
+
+#ifdef _UNICODE
+ CString& operator +=(char ch)
+ {
+ *this += (TCHAR)ch;
+ return *this;
+ }
+#endif
+
+ CString& operator +=(LPCTSTR lpsz)
+ {
+ ATLASSERT(lpsz == NULL || _IsValidString(lpsz));
+ ConcatInPlace(SafeStrlen(lpsz), lpsz);
+ return *this;
+ }
+
+ friend CString __stdcall operator +(const CString& string1, const CString& string2);
+ friend CString __stdcall operator +(const CString& string, TCHAR ch);
+ friend CString __stdcall operator +(TCHAR ch, const CString& string);
+#ifdef _UNICODE
+ friend CString __stdcall operator +(const CString& string, char ch);
+ friend CString __stdcall operator +(char ch, const CString& string);
+#endif
+ friend CString __stdcall operator +(const CString& string, LPCTSTR lpsz);
+ friend CString __stdcall operator +(LPCTSTR lpsz, const CString& string);
+
+ // string comparison
+ int Compare(LPCTSTR lpsz) const // straight character (MBCS/Unicode aware)
+ {
+ return _cstrcmp(m_pchData, lpsz);
+ }
+
+ int CompareNoCase(LPCTSTR lpsz) const // ignore case (MBCS/Unicode aware)
+ {
+ return _cstrcmpi(m_pchData, lpsz);
+ }
+
+#ifndef _WIN32_WCE
+ // CString::Collate is often slower than Compare but is MBSC/Unicode
+ // aware as well as locale-sensitive with respect to sort order.
+ int Collate(LPCTSTR lpsz) const // NLS aware
+ {
+ return _cstrcoll(m_pchData, lpsz);
+ }
+
+ int CollateNoCase(LPCTSTR lpsz) const // ignore case
+ {
+ return _cstrcolli(m_pchData, lpsz);
+ }
+#endif // !_WIN32_WCE
+
+ // simple sub-string extraction
+ CString Mid(int nFirst, int nCount) const
+ {
+ // out-of-bounds requests return sensible things
+ if (nFirst < 0)
+ nFirst = 0;
+ if (nCount < 0)
+ nCount = 0;
+
+ if (nFirst + nCount > GetData()->nDataLength)
+ nCount = GetData()->nDataLength - nFirst;
+ if (nFirst > GetData()->nDataLength)
+ nCount = 0;
+
+ CString dest;
+ AllocCopy(dest, nCount, nFirst, 0);
+ return dest;
+ }
+
+ CString Mid(int nFirst) const
+ {
+ return Mid(nFirst, GetData()->nDataLength - nFirst);
+ }
+
+ CString Left(int nCount) const
+ {
+ if (nCount < 0)
+ nCount = 0;
+ else if (nCount > GetData()->nDataLength)
+ nCount = GetData()->nDataLength;
+
+ CString dest;
+ AllocCopy(dest, nCount, 0, 0);
+ return dest;
+ }
+
+ CString Right(int nCount) const
+ {
+ if (nCount < 0)
+ nCount = 0;
+ else if (nCount > GetData()->nDataLength)
+ nCount = GetData()->nDataLength;
+
+ CString dest;
+ AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
+ return dest;
+ }
+
+ CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent
+ {
+ ATLASSERT(_IsValidString(lpszCharSet));
+ return Left(_cstrspn(m_pchData, lpszCharSet));
+ }
+
+ CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent
+ {
+ ATLASSERT(_IsValidString(lpszCharSet));
+ return Left(_cstrcspn(m_pchData, lpszCharSet));
+ }
+
+ // upper/lower/reverse conversion
+ void MakeUpper()
+ {
+ CopyBeforeWrite();
+ CharUpper(m_pchData);
+ }
+
+ void MakeLower()
+ {
+ CopyBeforeWrite();
+ CharLower(m_pchData);
+ }
+
+ void MakeReverse()
+ {
+ CopyBeforeWrite();
+ _cstrrev(m_pchData);
+ }
+
+ // trimming whitespace (either side)
+ void TrimRight()
+ {
+ CopyBeforeWrite();
+
+ // find beginning of trailing spaces by starting at beginning (DBCS aware)
+ LPTSTR lpsz = m_pchData;
+ LPTSTR lpszLast = NULL;
+ while (*lpsz != _T('\0'))
+ {
+ if (_cstrisspace(*lpsz))
+ {
+ if (lpszLast == NULL)
+ lpszLast = lpsz;
+ }
+ else
+ {
+ lpszLast = NULL;
+ }
+ lpsz = ::CharNext(lpsz);
+ }
+
+ if (lpszLast != NULL)
+ {
+ // truncate at trailing space start
+ *lpszLast = _T('\0');
+ GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
+ }
+ }
+
+ void TrimLeft()
+ {
+ CopyBeforeWrite();
+
+ // find first non-space character
+ LPCTSTR lpsz = m_pchData;
+ while (_cstrisspace(*lpsz))
+ lpsz = ::CharNext(lpsz);
+
+ // fix up data and length
+ int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
+ SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
+ GetData()->nDataLength = nDataLength;
+ }
+
+ // remove continuous occurrences of chTarget starting from right
+ void TrimRight(TCHAR chTarget)
+ {
+ // find beginning of trailing matches
+ // by starting at beginning (DBCS aware)
+
+ CopyBeforeWrite();
+ LPTSTR lpsz = m_pchData;
+ LPTSTR lpszLast = NULL;
+
+ while (*lpsz != _T('\0'))
+ {
+ if (*lpsz == chTarget)
+ {
+ if (lpszLast == NULL)
+ lpszLast = lpsz;
+ }
+ else
+ lpszLast = NULL;
+ lpsz = ::CharNext(lpsz);
+ }
+
+ if (lpszLast != NULL)
+ {
+ // truncate at left-most matching character
+ *lpszLast = _T('\0');
+ GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
+ }
+ }
+
+ // remove continuous occcurrences of characters in passed string, starting from right
+ void TrimRight(LPCTSTR lpszTargetList)
+ {
+ // find beginning of trailing matches by starting at beginning (DBCS aware)
+
+ CopyBeforeWrite();
+ LPTSTR lpsz = m_pchData;
+ LPTSTR lpszLast = NULL;
+
+ while (*lpsz != _T('\0'))
+ {
+ TCHAR* pNext = ::CharNext(lpsz);
+ if(pNext > lpsz + 1)
+ {
+ if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL)
+ {
+ if (lpszLast == NULL)
+ lpszLast = lpsz;
+ }
+ else
+ {
+ lpszLast = NULL;
+ }
+ }
+ else
+ {
+ if (_cstrchr(lpszTargetList, *lpsz) != NULL)
+ {
+ if (lpszLast == NULL)
+ lpszLast = lpsz;
+ }
+ else
+ {
+ lpszLast = NULL;
+ }
+ }
+
+ lpsz = pNext;
+ }
+
+ if (lpszLast != NULL)
+ {
+ // truncate at left-most matching character
+ *lpszLast = _T('\0');
+ GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
+ }
+ }
+
+ // remove continuous occurrences of chTarget starting from left
+ void TrimLeft(TCHAR chTarget)
+ {
+ // find first non-matching character
+
+ CopyBeforeWrite();
+ LPCTSTR lpsz = m_pchData;
+
+ while (chTarget == *lpsz)
+ lpsz = ::CharNext(lpsz);
+
+ if (lpsz != m_pchData)
+ {
+ // fix up data and length
+ int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
+ SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
+ GetData()->nDataLength = nDataLength;
+ }
+ }
+
+ // remove continuous occcurrences of characters in passed string, starting from left
+ void TrimLeft(LPCTSTR lpszTargets)
+ {
+ // if we're not trimming anything, we're not doing any work
+ if (SafeStrlen(lpszTargets) == 0)
+ return;
+
+ CopyBeforeWrite();
+ LPCTSTR lpsz = m_pchData;
+
+ while (*lpsz != _T('\0'))
+ {
+ TCHAR* pNext = ::CharNext(lpsz);
+ if(pNext > lpsz + 1)
+ {
+ if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL)
+ break;
+ }
+ else
+ {
+ if (_cstrchr(lpszTargets, *lpsz) == NULL)
+ break;
+ }
+ lpsz = pNext;
+ }
+
+ if (lpsz != m_pchData)
+ {
+ // fix up data and length
+ int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
+ SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
+ GetData()->nDataLength = nDataLength;
+ }
+ }
+
+ // advanced manipulation
+ // replace occurrences of chOld with chNew
+ int Replace(TCHAR chOld, TCHAR chNew)
+ {
+ int nCount = 0;
+
+ // short-circuit the nop case
+ if (chOld != chNew)
+ {
+ // otherwise modify each character that matches in the string
+ CopyBeforeWrite();
+ LPTSTR psz = m_pchData;
+ LPTSTR pszEnd = psz + GetData()->nDataLength;
+ while (psz < pszEnd)
+ {
+ // replace instances of the specified character only
+ if (*psz == chOld)
+ {
+ *psz = chNew;
+ nCount++;
+ }
+ psz = ::CharNext(psz);
+ }
+ }
+ return nCount;
+ }
+
+ // replace occurrences of substring lpszOld with lpszNew;
+ // empty lpszNew removes instances of lpszOld
+ int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
+ {
+ // can't have empty or NULL lpszOld
+
+ int nSourceLen = SafeStrlen(lpszOld);
+ if (nSourceLen == 0)
+ return 0;
+ int nReplacementLen = SafeStrlen(lpszNew);
+
+ // loop once to figure out the size of the result string
+ int nCount = 0;
+ LPTSTR lpszStart = m_pchData;
+ LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
+ LPTSTR lpszTarget = NULL;
+ while (lpszStart < lpszEnd)
+ {
+ while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)
+ {
+ nCount++;
+ lpszStart = lpszTarget + nSourceLen;
+ }
+ lpszStart += lstrlen(lpszStart) + 1;
+ }
+
+ // if any changes were made, make them
+ if (nCount > 0)
+ {
+ CopyBeforeWrite();
+
+ // if the buffer is too small, just allocate a new buffer (slow but sure)
+ int nOldLength = GetData()->nDataLength;
+ int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount;
+ if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
+ {
+ CStringData* pOldData = GetData();
+ LPTSTR pstr = m_pchData;
+ if(!AllocBuffer(nNewLength))
+ return -1;
+ SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR));
+ CString::Release(pOldData);
+ }
+ // else, we just do it in-place
+ lpszStart = m_pchData;
+ lpszEnd = m_pchData + GetData()->nDataLength;
+
+ // loop again to actually do the work
+ while (lpszStart < lpszEnd)
+ {
+ while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)
+ {
+ int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen);
+ int cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData);
+ SecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));
+ SecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR));
+ lpszStart = lpszTarget + nReplacementLen;
+ lpszStart[nBalance] = _T('\0');
+ nOldLength += (nReplacementLen - nSourceLen);
+ }
+ lpszStart += lstrlen(lpszStart) + 1;
+ }
+ ATLASSERT(m_pchData[nNewLength] == _T('\0'));
+ GetData()->nDataLength = nNewLength;
+ }
+
+ return nCount;
+ }
+
+ // remove occurrences of chRemove
+ int Remove(TCHAR chRemove)
+ {
+ CopyBeforeWrite();
+
+ LPTSTR pstrSource = m_pchData;
+ LPTSTR pstrDest = m_pchData;
+ LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
+
+ while (pstrSource < pstrEnd)
+ {
+ if (*pstrSource != chRemove)
+ {
+ *pstrDest = *pstrSource;
+ pstrDest = ::CharNext(pstrDest);
+ }
+ pstrSource = ::CharNext(pstrSource);
+ }
+ *pstrDest = _T('\0');
+ int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);
+ GetData()->nDataLength -= nCount;
+
+ return nCount;
+ }
+
+ // insert character at zero-based index; concatenates if index is past end of string
+ int Insert(int nIndex, TCHAR ch)
+ {
+ CopyBeforeWrite();
+
+ if (nIndex < 0)
+ nIndex = 0;
+
+ int nNewLength = GetData()->nDataLength;
+ if (nIndex > nNewLength)
+ nIndex = nNewLength;
+ nNewLength++;
+
+ if (GetData()->nAllocLength < nNewLength)
+ {
+ CStringData* pOldData = GetData();
+ LPTSTR pstr = m_pchData;
+ if(!AllocBuffer(nNewLength))
+ return -1;
+ SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
+ CString::Release(pOldData);
+ }
+
+ // move existing bytes down
+ SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));
+ m_pchData[nIndex] = ch;
+ GetData()->nDataLength = nNewLength;
+
+ return nNewLength;
+ }
+
+ // insert substring at zero-based index; concatenates if index is past end of string
+ int Insert(int nIndex, LPCTSTR pstr)
+ {
+ if (nIndex < 0)
+ nIndex = 0;
+
+ int nInsertLength = SafeStrlen(pstr);
+ int nNewLength = GetData()->nDataLength;
+ if (nInsertLength > 0)
+ {
+ CopyBeforeWrite();
+ if (nIndex > nNewLength)
+ nIndex = nNewLength;
+ nNewLength += nInsertLength;
+
+ if (GetData()->nAllocLength < nNewLength)
+ {
+ CStringData* pOldData = GetData();
+ LPTSTR pstr = m_pchData;
+ if(!AllocBuffer(nNewLength))
+ return -1;
+ SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
+ CString::Release(pOldData);
+ }
+
+ // move existing bytes down
+ SecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));
+ SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR));
+ GetData()->nDataLength = nNewLength;
+ }
+
+ return nNewLength;
+ }
+
+ // delete nCount characters starting at zero-based index
+ int Delete(int nIndex, int nCount = 1)
+ {
+ if (nIndex < 0)
+ nIndex = 0;
+ int nLength = GetData()->nDataLength;
+ if (nCount > 0 && nIndex < nLength)
+ {
+ if((nIndex + nCount) > nLength)
+ nCount = nLength - nIndex;
+ CopyBeforeWrite();
+ int nBytesToCopy = nLength - (nIndex + nCount) + 1;
+
+ SecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
+ nLength -= nCount;
+ GetData()->nDataLength = nLength;
+ }
+
+ return nLength;
+ }
+
+ // searching (return starting index, or -1 if not found)
+ // look for a single character match
+ int Find(TCHAR ch) const // like "C" strchr
+ {
+ return Find(ch, 0);
+ }
+
+ int ReverseFind(TCHAR ch) const
+ {
+ // find last single character
+ LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);
+
+ // return -1 if not found, distance from beginning otherwise
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
+ }
+
+ int Find(TCHAR ch, int nStart) const // starting at index
+ {
+ int nLength = GetData()->nDataLength;
+ if (nStart < 0 || nStart >= nLength)
+ return -1;
+
+ // find first single character
+ LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch);
+
+ // return -1 if not found and index otherwise
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
+ }
+
+ int FindOneOf(LPCTSTR lpszCharSet) const
+ {
+ ATLASSERT(_IsValidString(lpszCharSet));
+ LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
+ }
+
+ // look for a specific sub-string
+ // find a sub-string (like strstr)
+ int Find(LPCTSTR lpszSub) const // like "C" strstr
+ {
+ return Find(lpszSub, 0);
+ }
+
+ int Find(LPCTSTR lpszSub, int nStart) const // starting at index
+ {
+ ATLASSERT(_IsValidString(lpszSub));
+
+ int nLength = GetData()->nDataLength;
+ if (nStart < 0 || nStart > nLength)
+ return -1;
+
+ // find first matching substring
+ LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub);
+
+ // return -1 for not found, distance from beginning otherwise
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
+ }
+
+ // Concatentation for non strings
+ CString& Append(int n)
+ {
+ const int cchBuff = 12;
+ TCHAR szBuffer[cchBuff] = { 0 };
+ SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n);
+ ConcatInPlace(SafeStrlen(szBuffer), szBuffer);
+ return *this;
+ }
+
+ // simple formatting
+ // formatting (using wsprintf style formatting)
+ BOOL __cdecl Format(LPCTSTR lpszFormat, ...)
+ {
+ ATLASSERT(_IsValidString(lpszFormat));
+
+ va_list argList;
+ va_start(argList, lpszFormat);
+ BOOL bRet = FormatV(lpszFormat, argList);
+ va_end(argList);
+ return bRet;
+ }
+
+ BOOL __cdecl Format(UINT nFormatID, ...)
+ {
+ CString strFormat;
+ BOOL bRet = strFormat.LoadString(nFormatID);
+ ATLASSERT(bRet != 0);
+
+ va_list argList;
+ va_start(argList, nFormatID);
+ bRet = FormatV(strFormat, argList);
+ va_end(argList);
+ return bRet;
+ }
+
+ BOOL FormatV(LPCTSTR lpszFormat, va_list argList)
+ {
+ ATLASSERT(_IsValidString(lpszFormat));
+
+ enum _FormatModifiers
+ {
+ FORCE_ANSI = 0x10000,
+ FORCE_UNICODE = 0x20000,
+ FORCE_INT64 = 0x40000
+ };
+
+ va_list argListSave = argList;
+
+ // make a guess at the maximum length of the resulting string
+ int nMaxLen = 0;
+ for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz))
+ {
+ // handle '%' character, but watch out for '%%'
+ if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%'))
+ {
+ nMaxLen += (int)(::CharNext(lpsz) - lpsz);
+ continue;
+ }
+
+ int nItemLen = 0;
+
+ // handle '%' character with format
+ int nWidth = 0;
+ for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz))
+ {
+ // check for valid flags
+ if (*lpsz == _T('#'))
+ nMaxLen += 2; // for '0x'
+ else if (*lpsz == _T('*'))
+ nWidth = va_arg(argList, int);
+ else if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' '))
+ ;
+ else // hit non-flag character
+ break;
+ }
+ // get width and skip it
+ if (nWidth == 0)
+ {
+ // width indicated by
+ nWidth = _cstrtoi(lpsz);
+ for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
+ ;
+ }
+ ATLASSERT(nWidth >= 0);
+
+ int nPrecision = 0;
+ if (*lpsz == _T('.'))
+ {
+ // skip past '.' separator (width.precision)
+ lpsz = ::CharNext(lpsz);
+
+ // get precision and skip it
+ if (*lpsz == _T('*'))
+ {
+ nPrecision = va_arg(argList, int);
+ lpsz = ::CharNext(lpsz);
+ }
+ else
+ {
+ nPrecision = _cstrtoi(lpsz);
+ for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
+ ;
+ }
+ ATLASSERT(nPrecision >= 0);
+ }
+
+ // should be on type modifier or specifier
+ int nModifier = 0;
+ if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] == _T('4'))
+ {
+ lpsz += 3;
+ nModifier = FORCE_INT64;
+ }
+ else
+ {
+ switch (*lpsz)
+ {
+ // modifiers that affect size
+ case _T('h'):
+ nModifier = FORCE_ANSI;
+ lpsz = ::CharNext(lpsz);
+ break;
+ case _T('l'):
+ nModifier = FORCE_UNICODE;
+ lpsz = ::CharNext(lpsz);
+ break;
+
+ // modifiers that do not affect size
+ case _T('F'):
+ case _T('N'):
+ case _T('L'):
+ lpsz = ::CharNext(lpsz);
+ break;
+ }
+ }
+
+ // now should be on specifier
+ switch (*lpsz | nModifier)
+ {
+ // single characters
+ case _T('c'):
+ case _T('C'):
+ nItemLen = 2;
+ va_arg(argList, TCHAR);
+ break;
+ case _T('c') | FORCE_ANSI:
+ case _T('C') | FORCE_ANSI:
+ nItemLen = 2;
+ va_arg(argList, char);
+ break;
+ case _T('c') | FORCE_UNICODE:
+ case _T('C') | FORCE_UNICODE:
+ nItemLen = 2;
+ va_arg(argList, WCHAR);
+ break;
+
+ // strings
+ case _T('s'):
+ {
+ LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
+ if (pstrNextArg == NULL)
+ {
+ nItemLen = 6; // "(null)"
+ }
+ else
+ {
+ nItemLen = lstrlen(pstrNextArg);
+ nItemLen = max(1, nItemLen);
+ }
+ break;
+ }
+
+ case _T('S'):
+ {
+#ifndef _UNICODE
+ LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
+ if (pstrNextArg == NULL)
+ {
+ nItemLen = 6; // "(null)"
+ }
+ else
+ {
+ nItemLen = (int)wcslen(pstrNextArg);
+ nItemLen = max(1, nItemLen);
+ }
+#else // _UNICODE
+ LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
+ if (pstrNextArg == NULL)
+ {
+ nItemLen = 6; // "(null)"
+ }
+ else
+ {
+#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
+ nItemLen = ATL::lstrlenA(pstrNextArg);
+#else
+ nItemLen = lstrlenA(pstrNextArg);
+#endif
+ nItemLen = max(1, nItemLen);
+ }
+#endif // _UNICODE
+ break;
+ }
+
+ case _T('s') | FORCE_ANSI:
+ case _T('S') | FORCE_ANSI:
+ {
+ LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
+ if (pstrNextArg == NULL)
+ {
+ nItemLen = 6; // "(null)"
+ }
+ else
+ {
+#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
+ nItemLen = ATL::lstrlenA(pstrNextArg);
+#else
+ nItemLen = lstrlenA(pstrNextArg);
+#endif
+ nItemLen = max(1, nItemLen);
+ }
+ break;
+ }
+
+ case _T('s') | FORCE_UNICODE:
+ case _T('S') | FORCE_UNICODE:
+ {
+ LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
+ if (pstrNextArg == NULL)
+ {
+ nItemLen = 6; // "(null)"
+ }
+ else
+ {
+ nItemLen = (int)wcslen(pstrNextArg);
+ nItemLen = max(1, nItemLen);
+ }
+ break;
+ }
+ }
+
+ // adjust nItemLen for strings
+ if (nItemLen != 0)
+ {
+ nItemLen = max(nItemLen, nWidth);
+ if (nPrecision != 0)
+ nItemLen = min(nItemLen, nPrecision);
+ }
+ else
+ {
+ switch (*lpsz)
+ {
+ // integers
+ case _T('d'):
+ case _T('i'):
+ case _T('u'):
+ case _T('x'):
+ case _T('X'):
+ case _T('o'):
+ if (nModifier & FORCE_INT64)
+ va_arg(argList, __int64);
+ else
+ va_arg(argList, int);
+ nItemLen = 32;
+ nItemLen = max(nItemLen, nWidth + nPrecision);
+ break;
+
+#ifndef _ATL_USE_CSTRING_FLOAT
+ case _T('e'):
+ case _T('E'):
+ case _T('f'):
+ case _T('g'):
+ case _T('G'):
+ ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class.");
+#ifndef _DEBUG
+ ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
+#ifndef _WIN32_WCE
+ ::DebugBreak();
+#else // CE specific
+ DebugBreak();
+#endif // _WIN32_WCE
+#endif // !_DEBUG
+ break;
+#else // _ATL_USE_CSTRING_FLOAT
+ case _T('e'):
+ case _T('E'):
+ case _T('g'):
+ case _T('G'):
+ va_arg(argList, double);
+ nItemLen = 128;
+ nItemLen = max(nItemLen, nWidth + nPrecision);
+ break;
+ case _T('f'):
+ {
+ double f = va_arg(argList, double);
+ // 312 == strlen("-1+(309 zeroes).")
+ // 309 zeroes == max precision of a double
+ // 6 == adjustment in case precision is not specified,
+ // which means that the precision defaults to 6
+ int cchLen = max(nWidth, 312 + nPrecision + 6);
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR pszTemp = buff.Allocate(cchLen);
+ if(pszTemp != NULL)
+ {
+ SecureHelper::sprintf_x(pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f);
+ nItemLen = (int)_tcslen(pszTemp);
+ }
+ else
+ {
+ nItemLen = cchLen;
+ }
+ }
+ break;
+#endif // _ATL_USE_CSTRING_FLOAT
+
+ case _T('p'):
+ va_arg(argList, void*);
+ nItemLen = 32;
+ nItemLen = max(nItemLen, nWidth + nPrecision);
+ break;
+
+ // no output
+ case _T('n'):
+ va_arg(argList, int*);
+ break;
+
+ default:
+ ATLASSERT(FALSE); // unknown formatting option
+ }
+ }
+
+ // adjust nMaxLen for output nItemLen
+ nMaxLen += nItemLen;
+ }
+
+ if(GetBuffer(nMaxLen) == NULL)
+ return FALSE;
+#ifndef _ATL_USE_CSTRING_FLOAT
+ int nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);
+#else // _ATL_USE_CSTRING_FLOAT
+ int nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);
+#endif // _ATL_USE_CSTRING_FLOAT
+ nRet; // ref
+ ATLASSERT(nRet <= GetAllocLength());
+ ReleaseBuffer();
+
+ va_end(argListSave);
+ return TRUE;
+ }
+
+ // formatting for localization (uses FormatMessage API)
+ // formatting (using FormatMessage style formatting)
+ BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...)
+ {
+ // format message into temporary buffer lpszTemp
+ va_list argList;
+ va_start(argList, lpszFormat);
+ LPTSTR lpszTemp;
+ BOOL bRet = TRUE;
+
+ if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
+ bRet = FALSE;
+
+ // assign lpszTemp into the resulting string and free the temporary
+ *this = lpszTemp;
+ LocalFree(lpszTemp);
+ va_end(argList);
+ return bRet;
+ }
+
+ BOOL __cdecl FormatMessage(UINT nFormatID, ...)
+ {
+ // get format string from string table
+ CString strFormat;
+ BOOL bRetTmp = strFormat.LoadString(nFormatID);
+ bRetTmp; // ref
+ ATLASSERT(bRetTmp != 0);
+
+ // format message into temporary buffer lpszTemp
+ va_list argList;
+ va_start(argList, nFormatID);
+ LPTSTR lpszTemp;
+ BOOL bRet = TRUE;
+
+ if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
+ bRet = FALSE;
+
+ // assign lpszTemp into the resulting string and free lpszTemp
+ *this = lpszTemp;
+ LocalFree(lpszTemp);
+ va_end(argList);
+ return bRet;
+ }
+
+ // Windows support
+ BOOL LoadString(UINT nID) // load from string resource (255 chars max.)
+ {
+#ifdef _UNICODE
+ const int CHAR_FUDGE = 1; // one TCHAR unused is good enough
+#else
+ const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char
+#endif
+
+ // try fixed buffer first (to avoid wasting space in the heap)
+ TCHAR szTemp[256];
+ int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
+ int nLen = _LoadString(nID, szTemp, nCount);
+ if (nCount - nLen > CHAR_FUDGE)
+ {
+ *this = szTemp;
+ return (nLen > 0);
+ }
+
+ // try buffer size of 512, then larger size until entire string is retrieved
+ int nSize = 256;
+ do
+ {
+ nSize += 256;
+ LPTSTR lpstr = GetBuffer(nSize - 1);
+ if(lpstr == NULL)
+ {
+ nLen = 0;
+ break;
+ }
+ nLen = _LoadString(nID, lpstr, nSize);
+ } while (nSize - nLen <= CHAR_FUDGE);
+ ReleaseBuffer();
+
+ return (nLen > 0);
+ }
+
+#ifndef _UNICODE
+ // ANSI <-> OEM support (convert string in place)
+ void AnsiToOem()
+ {
+ CopyBeforeWrite();
+ ::AnsiToOem(m_pchData, m_pchData);
+ }
+
+ void OemToAnsi()
+ {
+ CopyBeforeWrite();
+ ::OemToAnsi(m_pchData, m_pchData);
+ }
+#endif
+
+#ifndef _ATL_NO_COM
+ // OLE BSTR support (use for OLE automation)
+ BSTR AllocSysString() const
+ {
+#if defined(_UNICODE) || defined(OLE2ANSI)
+ BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
+#else
+ int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
+ GetData()->nDataLength, NULL, NULL);
+ BSTR bstr = ::SysAllocStringLen(NULL, nLen);
+ if(bstr != NULL)
+ MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen);
+#endif
+ return bstr;
+ }
+
+ BSTR SetSysString(BSTR* pbstr) const
+ {
+#if defined(_UNICODE) || defined(OLE2ANSI)
+ ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
+#else
+ int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
+ GetData()->nDataLength, NULL, NULL);
+ if(::SysReAllocStringLen(pbstr, NULL, nLen))
+ MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen);
+#endif
+ ATLASSERT(*pbstr != NULL);
+ return *pbstr;
+ }
+#endif // !_ATL_NO_COM
+
+ // Access to string implementation buffer as "C" character array
+ LPTSTR GetBuffer(int nMinBufLength)
+ {
+ ATLASSERT(nMinBufLength >= 0);
+
+ if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
+ {
+ // we have to grow the buffer
+ CStringData* pOldData = GetData();
+ int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
+ if (nMinBufLength < nOldLen)
+ nMinBufLength = nOldLen;
+
+ if(!AllocBuffer(nMinBufLength))
+ return NULL;
+
+ SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));
+ GetData()->nDataLength = nOldLen;
+ CString::Release(pOldData);
+ }
+ ATLASSERT(GetData()->nRefs <= 1);
+
+ // return a pointer to the character storage for this string
+ ATLASSERT(m_pchData != NULL);
+ return m_pchData;
+ }
+
+ void ReleaseBuffer(int nNewLength = -1)
+ {
+ CopyBeforeWrite(); // just in case GetBuffer was not called
+
+ if (nNewLength == -1)
+ nNewLength = lstrlen(m_pchData); // zero terminated
+
+ ATLASSERT(nNewLength <= GetData()->nAllocLength);
+ GetData()->nDataLength = nNewLength;
+ m_pchData[nNewLength] = _T('\0');
+ }
+
+ LPTSTR GetBufferSetLength(int nNewLength)
+ {
+ ATLASSERT(nNewLength >= 0);
+
+ if(GetBuffer(nNewLength) == NULL)
+ return NULL;
+
+ GetData()->nDataLength = nNewLength;
+ m_pchData[nNewLength] = _T('\0');
+ return m_pchData;
+ }
+
+ void FreeExtra()
+ {
+ ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
+ if (GetData()->nDataLength != GetData()->nAllocLength)
+ {
+ CStringData* pOldData = GetData();
+ if(AllocBuffer(GetData()->nDataLength))
+ {
+ SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR));
+ ATLASSERT(m_pchData[GetData()->nDataLength] == _T('\0'));
+ CString::Release(pOldData);
+ }
+ }
+ ATLASSERT(GetData() != NULL);
+ }
+
+ // Use LockBuffer/UnlockBuffer to turn refcounting off
+ LPTSTR LockBuffer()
+ {
+ LPTSTR lpsz = GetBuffer(0);
+ if(lpsz != NULL)
+ GetData()->nRefs = -1;
+ return lpsz;
+ }
+
+ void UnlockBuffer()
+ {
+ ATLASSERT(GetData()->nRefs == -1);
+ if (GetData() != _atltmpDataNil)
+ GetData()->nRefs = 1;
+ }
+
+// Implementation
+public:
+ ~CString() // free any attached data
+ {
+ if (GetData() != _atltmpDataNil)
+ {
+ if (InterlockedDecrement(&GetData()->nRefs) <= 0)
+ delete[] (BYTE*)GetData();
+ }
+ }
+
+ int GetAllocLength() const
+ {
+ return GetData()->nAllocLength;
+ }
+
+ static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1)
+ {
+ return (lpsz != NULL) ? TRUE : FALSE;
+ }
+
+protected:
+ LPTSTR m_pchData; // pointer to ref counted string data
+
+ // implementation helpers
+ CStringData* GetData() const
+ {
+ ATLASSERT(m_pchData != NULL);
+ return ((CStringData*)m_pchData) - 1;
+ }
+
+ void Init()
+ {
+ m_pchData = _GetEmptyString().m_pchData;
+ }
+
+ BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
+ {
+ // will clone the data attached to this string
+ // allocating 'nExtraLen' characters
+ // Places results in uninitialized string 'dest'
+ // Will copy the part or all of original data to start of new string
+
+ BOOL bRet = FALSE;
+ int nNewLen = nCopyLen + nExtraLen;
+ if (nNewLen == 0)
+ {
+ dest.Init();
+ bRet = TRUE;
+ }
+ else if(nNewLen >= nCopyLen)
+ {
+ if(dest.AllocBuffer(nNewLen))
+ {
+ SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+ }
+
+ // always allocate one extra character for '\0' termination
+ // assumes [optimistically] that data length will equal allocation length
+ BOOL AllocBuffer(int nLen)
+ {
+ ATLASSERT(nLen >= 0);
+ ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra)
+
+ if (nLen == 0)
+ {
+ Init();
+ }
+ else
+ {
+ CStringData* pData = NULL;
+ ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]);
+ if(pData == NULL)
+ return FALSE;
+
+ pData->nRefs = 1;
+ pData->data()[nLen] = _T('\0');
+ pData->nDataLength = nLen;
+ pData->nAllocLength = nLen;
+ m_pchData = pData->data();
+ }
+
+ return TRUE;
+ }
+
+ // Assignment operators
+ // All assign a new value to the string
+ // (a) first see if the buffer is big enough
+ // (b) if enough room, copy on top of old buffer, set size and type
+ // (c) otherwise free old string data, and create a new one
+ //
+ // All routines return the new string (but as a 'const CString&' so that
+ // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
+ //
+ void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
+ {
+ if(AllocBeforeWrite(nSrcLen))
+ {
+ SecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR));
+ GetData()->nDataLength = nSrcLen;
+ m_pchData[nSrcLen] = _T('\0');
+ }
+ }
+
+ // Concatenation
+ // NOTE: "operator +" is done as friend functions for simplicity
+ // There are three variants:
+ // CString + CString
+ // and for ? = TCHAR, LPCTSTR
+ // CString + ?
+ // ? + CString
+ BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data)
+ {
+ // -- master concatenation routine
+ // Concatenate two sources
+ // -- assume that 'this' is a new CString object
+
+ BOOL bRet = TRUE;
+ int nNewLen = nSrc1Len + nSrc2Len;
+ if(nNewLen < nSrc1Len || nNewLen < nSrc2Len)
+ {
+ bRet = FALSE;
+ }
+ else if(nNewLen != 0)
+ {
+ bRet = AllocBuffer(nNewLen);
+ if (bRet)
+ {
+ SecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR));
+ SecureHelper::memcpy_x(m_pchData + nSrc1Len, (nNewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR));
+ }
+ }
+ return bRet;
+ }
+
+ void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
+ {
+ // -- the main routine for += operators
+
+ // concatenating an empty string is a no-op!
+ if (nSrcLen == 0)
+ return;
+
+ // if the buffer is too small, or we have a width mis-match, just
+ // allocate a new buffer (slow but sure)
+ if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
+ {
+ // we have to grow the buffer, use the ConcatCopy routine
+ CStringData* pOldData = GetData();
+ if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData))
+ {
+ ATLASSERT(pOldData != NULL);
+ CString::Release(pOldData);
+ }
+ }
+ else
+ {
+ // fast concatenation when buffer big enough
+ SecureHelper::memcpy_x(m_pchData + GetData()->nDataLength, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR));
+ GetData()->nDataLength += nSrcLen;
+ ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
+ m_pchData[GetData()->nDataLength] = _T('\0');
+ }
+ }
+
+ void CopyBeforeWrite()
+ {
+ if (GetData()->nRefs > 1)
+ {
+ CStringData* pData = GetData();
+ Release();
+ if(AllocBuffer(pData->nDataLength))
+ SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR));
+ }
+ ATLASSERT(GetData()->nRefs <= 1);
+ }
+
+ BOOL AllocBeforeWrite(int nLen)
+ {
+ BOOL bRet = TRUE;
+ if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
+ {
+ Release();
+ bRet = AllocBuffer(nLen);
+ }
+ ATLASSERT(GetData()->nRefs <= 1);
+ return bRet;
+ }
+
+ void Release()
+ {
+ if (GetData() != _atltmpDataNil)
+ {
+ ATLASSERT(GetData()->nRefs != 0);
+ if (InterlockedDecrement(&GetData()->nRefs) <= 0)
+ delete[] (BYTE*)GetData();
+ Init();
+ }
+ }
+
+ static void PASCAL Release(CStringData* pData)
+ {
+ if (pData != _atltmpDataNil)
+ {
+ ATLASSERT(pData->nRefs != 0);
+ if (InterlockedDecrement(&pData->nRefs) <= 0)
+ delete[] (BYTE*)pData;
+ }
+ }
+
+ static int PASCAL SafeStrlen(LPCTSTR lpsz)
+ {
+ return (lpsz == NULL) ? 0 : lstrlen(lpsz);
+ }
+
+ static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
+ {
+#ifdef _DEBUG
+ // LoadString without annoying warning from the Debug kernel if the
+ // segment containing the string is not present
+ if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID >> 4) + 1), RT_STRING) == NULL)
+ {
+ lpszBuf[0] = _T('\0');
+ return 0; // not found
+ }
+#endif // _DEBUG
+
+ int nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID, lpszBuf, nMaxBuf);
+ if (nLen == 0)
+ lpszBuf[0] = _T('\0');
+
+ return nLen;
+ }
+
+ static const CString& __stdcall _GetEmptyString()
+ {
+ return *(CString*)&_atltmpPchNil;
+ }
+
+// CString conversion helpers
+ static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
+ {
+ if (count == 0 && mbstr != NULL)
+ return 0;
+
+ int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL);
+ ATLASSERT(mbstr == NULL || result <= (int)count);
+ if (result > 0)
+ mbstr[result - 1] = 0;
+ return result;
+ }
+
+ static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
+ {
+ if (count == 0 && wcstr != NULL)
+ return 0;
+
+ int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count);
+ ATLASSERT(wcstr == NULL || result <= (int)count);
+ if (result > 0)
+ wcstr[result - 1] = 0;
+ return result;
+ }
+
+// Helpers to avoid CRT startup code
+#ifdef _ATL_MIN_CRT
+ static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
+ {
+ // strchr for '\0' should succeed
+ while (*p != 0)
+ {
+ if (*p == ch)
+ break;
+ p = ::CharNext(p);
+ }
+ return (*p == ch) ? p : NULL;
+ }
+
+ static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
+ {
+ const TCHAR* lpsz = NULL;
+ while (*p != 0)
+ {
+ if (*p == ch)
+ lpsz = p;
+ p = ::CharNext(p);
+ }
+ return lpsz;
+ }
+
+ static TCHAR* _cstrrev(TCHAR* pStr)
+ {
+ // optimize NULL, zero-length, and single-char case
+ if ((pStr == NULL) || (pStr[0] == _T('\0')) || (pStr[1] == _T('\0')))
+ return pStr;
+
+ TCHAR* p = pStr;
+
+ while (*p != 0)
+ {
+ TCHAR* pNext = ::CharNext(p);
+ if(pNext > p + 1)
+ {
+ char p1 = *(char*)p;
+ *(char*)p = *(char*)(p + 1);
+ *(char*)(p + 1) = p1;
+ }
+ p = pNext;
+ }
+
+ p--;
+ TCHAR* q = pStr;
+
+ while (q < p)
+ {
+ TCHAR t = *q;
+ *q = *p;
+ *p = t;
+ q++;
+ p--;
+ }
+ return pStr;
+ }
+
+ static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ int nLen = lstrlen(pCharSet);
+ if (nLen == 0)
+ return (TCHAR*)pStr;
+
+ const TCHAR* pRet = NULL;
+ const TCHAR* pCur = pStr;
+ while((pCur = _cstrchr(pCur, *pCharSet)) != NULL)
+ {
+ if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0)
+ {
+ pRet = pCur;
+ break;
+ }
+ pCur = ::CharNext(pCur);
+ }
+ return pRet;
+ }
+
+ static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ int nRet = 0;
+ const TCHAR* p = pStr;
+ while (*p != 0)
+ {
+ const TCHAR* pNext = ::CharNext(p);
+ if(pNext > p + 1)
+ {
+ if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL)
+ break;
+ nRet += 2;
+ }
+ else
+ {
+ if(_cstrchr(pCharSet, *p) == NULL)
+ break;
+ nRet++;
+ }
+ p = pNext;
+ }
+ return nRet;
+ }
+
+ static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ int nRet = 0;
+ TCHAR* p = (TCHAR*)pStr;
+ while (*p != 0)
+ {
+ TCHAR* pNext = ::CharNext(p);
+ if(pNext > p + 1)
+ {
+ if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL)
+ break;
+ nRet += 2;
+ }
+ else
+ {
+ if(_cstrchr(pCharSet, *p) != NULL)
+ break;
+ nRet++;
+ }
+ p = pNext;
+ }
+ return nRet;
+ }
+
+ static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
+ {
+ int n = _cstrcspn(p, lpszCharSet);
+ return (p[n] != 0) ? &p[n] : NULL;
+ }
+
+ static int _cstrisdigit(TCHAR ch)
+ {
+ WORD type;
+ GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
+ return (type & C1_DIGIT) == C1_DIGIT;
+ }
+
+ static int _cstrisspace(TCHAR ch)
+ {
+ WORD type;
+ GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
+ return (type & C1_SPACE) == C1_SPACE;
+ }
+
+ static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return lstrcmp(pstrOne, pstrOther);
+ }
+
+ static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return lstrcmpi(pstrOne, pstrOther);
+ }
+
+ static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);
+ ATLASSERT(nRet != 0);
+ return nRet - 2; // convert to strcmp convention
+ }
+
+ static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1);
+ ATLASSERT(nRet != 0);
+ return nRet - 2; // convert to strcmp convention
+ }
+
+ static int _cstrtoi(const TCHAR* nptr)
+ {
+ int c; // current char
+ int total; // current total
+ int sign; // if '-', then negative, otherwise positive
+
+ while (_cstrisspace(*nptr))
+ ++nptr;
+
+ c = (int)(_TUCHAR)*nptr++;
+ sign = c; // save sign indication
+ if (c == _T('-') || c == _T('+'))
+ c = (int)(_TUCHAR)*nptr++; // skip sign
+
+ total = 0;
+
+ while (_cstrisdigit((TCHAR)c))
+ {
+ total = 10 * total + (c - '0'); // accumulate digit
+ c = (int)(_TUCHAR)*nptr++; // get next char
+ }
+
+ if (sign == '-')
+ return -total;
+ else
+ return total; // return result, negated if necessary
+ }
+#else // !_ATL_MIN_CRT
+ static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
+ {
+ return _tcschr(p, ch);
+ }
+
+ static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
+ {
+ return _tcsrchr(p, ch);
+ }
+
+ static TCHAR* _cstrrev(TCHAR* pStr)
+ {
+ return _tcsrev(pStr);
+ }
+
+ static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ return _tcsstr(pStr, pCharSet);
+ }
+
+ static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ return (int)_tcsspn(pStr, pCharSet);
+ }
+
+ static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
+ {
+ return (int)_tcscspn(pStr, pCharSet);
+ }
+
+ static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
+ {
+ return _tcspbrk(p, lpszCharSet);
+ }
+
+ static int _cstrisdigit(TCHAR ch)
+ {
+ return _istdigit(ch);
+ }
+
+ static int _cstrisspace(TCHAR ch)
+ {
+ return _istspace((_TUCHAR)ch);
+ }
+
+ static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return _tcscmp(pstrOne, pstrOther);
+ }
+
+ static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return _tcsicmp(pstrOne, pstrOther);
+ }
+
+#ifndef _WIN32_WCE
+ static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return _tcscoll(pstrOne, pstrOther);
+ }
+
+ static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
+ {
+ return _tcsicoll(pstrOne, pstrOther);
+ }
+#endif // !_WIN32_WCE
+
+ static int _cstrtoi(const TCHAR* nptr)
+ {
+ return _ttoi(nptr);
+ }
+#endif // !_ATL_MIN_CRT
+
+ static const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2)
+ {
+ const TCHAR* lpsz = NULL;
+ while (*p != 0)
+ {
+ if (*p == ch1 && *(p + 1) == ch2)
+ {
+ lpsz = p;
+ break;
+ }
+ p = ::CharNext(p);
+ }
+ return lpsz;
+ }
+};
+
+
+// Compare helpers
+
+inline bool __stdcall operator ==(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) == 0; }
+
+inline bool __stdcall operator ==(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) == 0; }
+
+inline bool __stdcall operator ==(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) == 0; }
+
+inline bool __stdcall operator !=(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) != 0; }
+
+inline bool __stdcall operator !=(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) != 0; }
+
+inline bool __stdcall operator !=(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) != 0; }
+
+inline bool __stdcall operator <(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) < 0; }
+
+inline bool __stdcall operator <(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) < 0; }
+
+inline bool __stdcall operator <(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) > 0; }
+
+inline bool __stdcall operator >(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) > 0; }
+
+inline bool __stdcall operator >(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) > 0; }
+
+inline bool __stdcall operator >(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) < 0; }
+
+inline bool __stdcall operator <=(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) <= 0; }
+
+inline bool __stdcall operator <=(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) <= 0; }
+
+inline bool __stdcall operator <=(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) >= 0; }
+
+inline bool __stdcall operator >=(const CString& s1, const CString& s2)
+{ return s1.Compare(s2) >= 0; }
+
+inline bool __stdcall operator >=(const CString& s1, LPCTSTR s2)
+{ return s1.Compare(s2) >= 0; }
+
+inline bool __stdcall operator >=(LPCTSTR s1, const CString& s2)
+{ return s2.Compare(s1) <= 0; }
+
+
+// CString "operator +" functions
+
+inline CString __stdcall operator +(const CString& string1, const CString& string2)
+{
+ CString s;
+ s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData);
+ return s;
+}
+
+inline CString __stdcall operator +(const CString& string, TCHAR ch)
+{
+ CString s;
+ s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch);
+ return s;
+}
+
+inline CString __stdcall operator +(TCHAR ch, const CString& string)
+{
+ CString s;
+ s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
+ return s;
+}
+
+#ifdef _UNICODE
+inline CString __stdcall operator +(const CString& string, char ch)
+{
+ return string + (TCHAR)ch;
+}
+
+inline CString __stdcall operator +(char ch, const CString& string)
+{
+ return (TCHAR)ch + string;
+}
+#endif // _UNICODE
+
+inline CString __stdcall operator +(const CString& string, LPCTSTR lpsz)
+{
+ ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));
+ CString s;
+ s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz);
+ return s;
+}
+
+inline CString __stdcall operator +(LPCTSTR lpsz, const CString& string)
+{
+ ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));
+ CString s;
+ s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData);
+ return s;
+}
+
+#endif // !_WTL_NO_CSTRING
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRecentDocumentList - MRU List Support
+
+#ifndef _WIN32_WCE
+
+#ifndef _WTL_MRUEMPTY_TEXT
+ #define _WTL_MRUEMPTY_TEXT _T("(empty)")
+#endif
+
+// forward declaration
+inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen);
+
+template <class T, int t_cchItemLen = MAX_PATH, int t_nFirstID = ID_FILE_MRU_FIRST, int t_nLastID = ID_FILE_MRU_LAST>
+class CRecentDocumentListBase
+{
+public:
+// Declarations
+ struct _DocEntry
+ {
+ TCHAR szDocName[t_cchItemLen];
+ bool operator ==(const _DocEntry& de) const
+ { return (lstrcmpi(szDocName, de.szDocName) == 0); }
+ };
+
+ enum
+ {
+ m_nMaxEntries_Min = 2,
+ m_nMaxEntries_Max = t_nLastID - t_nFirstID + 1,
+ m_cchMaxItemLen_Min = 6,
+ m_cchMaxItemLen_Max = t_cchItemLen,
+ m_cchItemNameLen = 11
+ };
+
+// Data members
+ ATL::CSimpleArray<_DocEntry> m_arrDocs;
+ int m_nMaxEntries; // default is 4
+ HMENU m_hMenu;
+
+ TCHAR m_szNoEntries[t_cchItemLen];
+
+ int m_cchMaxItemLen;
+
+// Constructor
+ CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1)
+ {
+ // These ASSERTs verify values of the template arguments
+ ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min);
+ ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min);
+ }
+
+// Attributes
+ HMENU GetMenuHandle() const
+ {
+ return m_hMenu;
+ }
+
+ void SetMenuHandle(HMENU hMenu)
+ {
+ ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));
+ m_hMenu = hMenu;
+ if(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0))
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ SecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE);
+ }
+ }
+
+ int GetMaxEntries() const
+ {
+ return m_nMaxEntries;
+ }
+
+ void SetMaxEntries(int nMaxEntries)
+ {
+ ATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_nMaxEntries_Max);
+ if(nMaxEntries < m_nMaxEntries_Min)
+ nMaxEntries = m_nMaxEntries_Min;
+ else if(nMaxEntries > m_nMaxEntries_Max)
+ nMaxEntries = m_nMaxEntries_Max;
+ m_nMaxEntries = nMaxEntries;
+ }
+
+ int GetMaxItemLength() const
+ {
+ return m_cchMaxItemLen;
+ }
+
+ void SetMaxItemLength(int cchMaxLen)
+ {
+ ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1);
+ if(cchMaxLen != -1)
+ {
+ if(cchMaxLen < m_cchMaxItemLen_Min)
+ cchMaxLen = m_cchMaxItemLen_Min;
+ else if(cchMaxLen > m_cchMaxItemLen_Max)
+ cchMaxLen = m_cchMaxItemLen_Max;
+ }
+ m_cchMaxItemLen = cchMaxLen;
+ T* pT = static_cast<T*>(this);
+ pT->UpdateMenu();
+ }
+
+// Operations
+ BOOL AddToList(LPCTSTR lpstrDocName)
+ {
+ _DocEntry de;
+ errno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE);
+ if(nRet != 0 && nRet != STRUNCATE)
+ return FALSE;
+
+ for(int i = 0; i < m_arrDocs.GetSize(); i++)
+ {
+ if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0)
+ {
+ m_arrDocs.RemoveAt(i);
+ break;
+ }
+ }
+
+ if(m_arrDocs.GetSize() == m_nMaxEntries)
+ m_arrDocs.RemoveAt(0);
+
+ BOOL bRet = m_arrDocs.Add(de);
+ if(bRet)
+ {
+ T* pT = static_cast<T*>(this);
+ bRet = pT->UpdateMenu();
+ }
+ return bRet;
+ }
+
+ // This function is deprecated because it is not safe.
+ // Use the version below that accepts the buffer length.
+#if (_MSC_VER >= 1300)
+ __declspec(deprecated)
+#endif
+ BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/)
+ {
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength)
+ {
+ int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
+ if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
+ return FALSE;
+ if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength)
+ return FALSE;
+ SecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName);
+
+ return TRUE;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ BOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName)
+ {
+ int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
+ if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
+ return FALSE;
+ strDocName = m_arrDocs[nIndex].szDocName;
+ return TRUE;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL RemoveFromList(int nItemID)
+ {
+ int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
+ BOOL bRet = m_arrDocs.RemoveAt(nIndex);
+ if(bRet)
+ {
+ T* pT = static_cast<T*>(this);
+ bRet = pT->UpdateMenu();
+ }
+ return bRet;
+ }
+
+ BOOL MoveToTop(int nItemID)
+ {
+ int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
+ if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
+ return FALSE;
+ _DocEntry de;
+ de = m_arrDocs[nIndex];
+ m_arrDocs.RemoveAt(nIndex);
+ BOOL bRet = m_arrDocs.Add(de);
+ if(bRet)
+ {
+ T* pT = static_cast<T*>(this);
+ bRet = pT->UpdateMenu();
+ }
+ return bRet;
+ }
+
+ BOOL ReadFromRegistry(LPCTSTR lpstrRegKey)
+ {
+ T* pT = static_cast<T*>(this);
+ CRegKeyEx rkParent;
+ CRegKeyEx rk;
+
+ LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey);
+ if(lRet != ERROR_SUCCESS)
+ return FALSE;
+ lRet = rk.Open(rkParent, pT->GetRegKeyName());
+ if(lRet != ERROR_SUCCESS)
+ return FALSE;
+
+ DWORD dwRet = 0;
+ lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet);
+ if(lRet != ERROR_SUCCESS)
+ return FALSE;
+ SetMaxEntries(dwRet);
+
+ m_arrDocs.RemoveAll();
+
+ TCHAR szRetString[t_cchItemLen] = { 0 };
+ _DocEntry de;
+
+ for(int nItem = m_nMaxEntries; nItem > 0; nItem--)
+ {
+ TCHAR szBuff[m_cchItemNameLen] = { 0 };
+ SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
+ ULONG ulCount = t_cchItemLen;
+ lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount);
+ if(lRet == ERROR_SUCCESS)
+ {
+ SecureHelper::strcpy_x(de.szDocName, _countof(de.szDocName), szRetString);
+ m_arrDocs.Add(de);
+ }
+ }
+
+ rk.Close();
+ rkParent.Close();
+
+ return pT->UpdateMenu();
+ }
+
+ BOOL WriteToRegistry(LPCTSTR lpstrRegKey)
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ CRegKeyEx rkParent;
+ CRegKeyEx rk;
+
+ LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey);
+ if(lRet != ERROR_SUCCESS)
+ return FALSE;
+ lRet = rk.Create(rkParent, pT->GetRegKeyName());
+ if(lRet != ERROR_SUCCESS)
+ return FALSE;
+
+ lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries);
+ ATLASSERT(lRet == ERROR_SUCCESS);
+
+ // set new values
+ int nItem;
+ for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--)
+ {
+ TCHAR szBuff[m_cchItemNameLen] = { 0 };
+ SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
+ TCHAR szDocName[t_cchItemLen] = { 0 };
+ GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen);
+ lRet = rk.SetStringValue(szBuff, szDocName);
+ ATLASSERT(lRet == ERROR_SUCCESS);
+ }
+
+ // delete unused keys
+ for(nItem = m_arrDocs.GetSize() + 1; nItem < m_nMaxEntries_Max; nItem++)
+ {
+ TCHAR szBuff[m_cchItemNameLen] = { 0 };
+ SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
+ rk.DeleteValue(szBuff);
+ }
+
+ rk.Close();
+ rkParent.Close();
+
+ return TRUE;
+ }
+
+// Implementation
+ BOOL UpdateMenu()
+ {
+ if(m_hMenu == NULL)
+ return FALSE;
+ ATLASSERT(::IsMenu(m_hMenu));
+
+ int nItems = ::GetMenuItemCount(m_hMenu);
+ int nInsertPoint;
+ for(nInsertPoint = 0; nInsertPoint < nItems; nInsertPoint++)
+ {
+ CMenuItemInfo mi;
+ mi.fMask = MIIM_ID;
+ ::GetMenuItemInfo(m_hMenu, nInsertPoint, TRUE, &mi);
+ if (mi.wID == t_nFirstID)
+ break;
+ }
+ ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = t_nFirstID");
+
+ int nItem;
+ for(nItem = t_nFirstID; nItem < t_nFirstID + m_nMaxEntries; nItem++)
+ {
+ // keep the first one as an insertion point
+ if (nItem != t_nFirstID)
+ ::DeleteMenu(m_hMenu, nItem, MF_BYCOMMAND);
+ }
+
+ TCHAR szItemText[t_cchItemLen + 6] = { 0 }; // add space for &, 2 digits, and a space
+ int nSize = m_arrDocs.GetSize();
+ nItem = 0;
+ if(nSize > 0)
+ {
+ for(nItem = 0; nItem < nSize; nItem++)
+ {
+ if(m_cchMaxItemLen == -1)
+ {
+ SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName);
+ }
+ else
+ {
+ TCHAR szBuff[t_cchItemLen] = { 0 };
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen);
+ bRet; // avoid level 4 warning
+ ATLASSERT(bRet);
+ SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, szBuff);
+ }
+ ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText);
+ }
+ }
+ else // empty
+ {
+ ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries);
+ ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED);
+ nItem++;
+ }
+ ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION);
+
+ return TRUE;
+ }
+
+// Overrideables
+ // override to provide a different method of compacting document names
+ static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
+ {
+ return AtlCompactPath(lpstrOut, lpstrIn, cchLen);
+ }
+
+ static LPCTSTR GetRegKeyName()
+ {
+ return _T("Recent Document List");
+ }
+
+ static LPCTSTR GetRegCountName()
+ {
+ return _T("DocumentCount");
+ }
+
+ static LPCTSTR GetRegItemName()
+ {
+ // Note: This string is a format string used with wsprintf().
+ // Resulting formatted string must be m_cchItemNameLen or less
+ // characters long, including the terminating null character.
+ return _T("Document%i");
+ }
+
+ static LPCTSTR GetMRUEmptyText()
+ {
+ return _WTL_MRUEMPTY_TEXT;
+ }
+};
+
+class CRecentDocumentList : public CRecentDocumentListBase<CRecentDocumentList>
+{
+public:
+// nothing here
+};
+
+#endif // _WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFindFile - file search helper class
+
+class CFindFile
+{
+public:
+// Data members
+ WIN32_FIND_DATA m_fd;
+ TCHAR m_lpszRoot[MAX_PATH];
+ TCHAR m_chDirSeparator;
+ HANDLE m_hFind;
+ BOOL m_bFound;
+
+// Constructor/destructor
+ CFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE)
+ { }
+
+ ~CFindFile()
+ {
+ Close();
+ }
+
+// Attributes
+ ULONGLONG GetFileSize() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ ULARGE_INTEGER nFileSize = { 0 };
+
+ if(m_bFound)
+ {
+ nFileSize.LowPart = m_fd.nFileSizeLow;
+ nFileSize.HighPart = m_fd.nFileSizeHigh;
+ }
+ else
+ {
+ nFileSize.QuadPart = 0;
+ }
+
+ return nFileSize.QuadPart;
+ }
+
+ BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const
+ {
+ ATLASSERT(m_hFind != NULL);
+ if(lstrlen(m_fd.cFileName) >= cchLength)
+ return FALSE;
+
+ if(m_bFound)
+ SecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cFileName);
+
+ return m_bFound;
+ }
+
+ BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ int nLen = lstrlen(m_lpszRoot);
+#ifndef _WIN32_WCE
+ ATLASSERT(nLen > 0);
+ if(nLen == 0)
+ return FALSE;
+
+ bool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/'));
+#else // CE specific
+ // allow diskless devices (nLen == 0)
+ bool bAddSep = ((nLen == 0) || (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/')));
+#endif // _WIN32_WCE
+
+ if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength)
+ return FALSE;
+
+ SecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot);
+
+ if(bAddSep)
+ {
+ TCHAR szSeparator[2] = { m_chDirSeparator, 0 };
+ SecureHelper::strcat_x(lpstrFilePath, cchLength, szSeparator);
+ }
+
+ SecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName);
+
+ return TRUE;
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ TCHAR szBuff[MAX_PATH] = { 0 };
+ if(!GetFileName(szBuff, MAX_PATH))
+ return FALSE;
+
+ if(lstrlen(szBuff) >= cchLength || cchLength < 1)
+ return FALSE;
+
+ // find the last dot
+ LPTSTR pstrDot = (LPTSTR)_cstrrchr(szBuff, _T('.'));
+ if(pstrDot != NULL)
+ *pstrDot = 0;
+
+ SecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff);
+
+ return TRUE;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ TCHAR szBuff[MAX_PATH] = { 0 };
+ if(!GetFilePath(szBuff, MAX_PATH))
+ return FALSE;
+ LPCTSTR lpstrFileURLPrefix = _T("file://");
+ if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength)
+ return FALSE;
+ SecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPrefix);
+ SecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff);
+
+ return TRUE;
+ }
+
+ BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const
+ {
+ ATLASSERT(m_hFind != NULL);
+ if(lstrlen(m_lpszRoot) >= cchLength)
+ return FALSE;
+
+ SecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot);
+
+ return TRUE;
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ _CSTRING_NS::CString GetFileName() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ _CSTRING_NS::CString ret;
+
+ if(m_bFound)
+ ret = m_fd.cFileName;
+ return ret;
+ }
+
+ _CSTRING_NS::CString GetFilePath() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ _CSTRING_NS::CString strResult = m_lpszRoot;
+ int nLen = strResult.GetLength();
+#ifndef _WIN32_WCE
+ ATLASSERT(nLen > 0);
+ if(nLen == 0)
+ return strResult;
+
+ if((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/')))
+#else // CE specific
+ // allow diskless devices (nLen == 0)
+ if((nLen == 0) || ((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/'))))
+#endif // _WIN32_WCE
+ strResult += m_chDirSeparator;
+ strResult += GetFileName();
+ return strResult;
+ }
+
+#ifndef _WIN32_WCE
+ _CSTRING_NS::CString GetFileTitle() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ _CSTRING_NS::CString strResult;
+ GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH);
+ strResult.ReleaseBuffer();
+
+ return strResult;
+ }
+#endif // !_WIN32_WCE
+
+ _CSTRING_NS::CString GetFileURL() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ _CSTRING_NS::CString strResult("file://");
+ strResult += GetFilePath();
+ return strResult;
+ }
+
+ _CSTRING_NS::CString GetRoot() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ _CSTRING_NS::CString str = m_lpszRoot;
+ return str;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ BOOL GetLastWriteTime(FILETIME* pTimeStamp) const
+ {
+ ATLASSERT(m_hFind != NULL);
+ ATLASSERT(pTimeStamp != NULL);
+
+ if(m_bFound && pTimeStamp != NULL)
+ {
+ *pTimeStamp = m_fd.ftLastWriteTime;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ BOOL GetLastAccessTime(FILETIME* pTimeStamp) const
+ {
+ ATLASSERT(m_hFind != NULL);
+ ATLASSERT(pTimeStamp != NULL);
+
+ if(m_bFound && pTimeStamp != NULL)
+ {
+ *pTimeStamp = m_fd.ftLastAccessTime;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ BOOL GetCreationTime(FILETIME* pTimeStamp) const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ if(m_bFound && pTimeStamp != NULL)
+ {
+ *pTimeStamp = m_fd.ftCreationTime;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ BOOL MatchesMask(DWORD dwMask) const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ if(m_bFound)
+ return ((m_fd.dwFileAttributes & dwMask) != 0);
+
+ return FALSE;
+ }
+
+ BOOL IsDots() const
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ // return TRUE if the file name is "." or ".." and
+ // the file is a directory
+
+ BOOL bResult = FALSE;
+ if(m_bFound && IsDirectory())
+ {
+ if(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\0'))))
+ bResult = TRUE;
+ }
+
+ return bResult;
+ }
+
+ BOOL IsReadOnly() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_READONLY);
+ }
+
+ BOOL IsDirectory() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_DIRECTORY);
+ }
+
+ BOOL IsCompressed() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_COMPRESSED);
+ }
+
+ BOOL IsSystem() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_SYSTEM);
+ }
+
+ BOOL IsHidden() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_HIDDEN);
+ }
+
+ BOOL IsTemporary() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_TEMPORARY);
+ }
+
+ BOOL IsNormal() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_NORMAL);
+ }
+
+ BOOL IsArchived() const
+ {
+ return MatchesMask(FILE_ATTRIBUTE_ARCHIVE);
+ }
+
+// Operations
+ BOOL FindFile(LPCTSTR pstrName = NULL)
+ {
+ Close();
+
+ if(pstrName == NULL)
+ {
+ pstrName = _T("*.*");
+ }
+ else if(lstrlen(pstrName) >= MAX_PATH)
+ {
+ ATLASSERT(FALSE);
+ return FALSE;
+ }
+
+ SecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName);
+
+ m_hFind = ::FindFirstFile(pstrName, &m_fd);
+
+ if(m_hFind == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+#ifndef _WIN32_WCE
+ bool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRoot, NULL) != 0);
+#else // CE specific
+ errno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lpszRoot), pstrName, _TRUNCATE);
+ bool bFullPath = (nRet == 0 || nRet == STRUNCATE);
+#endif // _WIN32_WCE
+
+ // passed name isn't a valid path but was found by the API
+ ATLASSERT(bFullPath);
+ if(!bFullPath)
+ {
+ Close();
+ ::SetLastError(ERROR_INVALID_NAME);
+ return FALSE;
+ }
+ else
+ {
+ // find the last forward or backward whack
+ LPTSTR pstrBack = (LPTSTR)_cstrrchr(m_lpszRoot, _T('\\'));
+ LPTSTR pstrFront = (LPTSTR)_cstrrchr(m_lpszRoot, _T('/'));
+
+ if(pstrFront != NULL || pstrBack != NULL)
+ {
+ if(pstrFront == NULL)
+ pstrFront = m_lpszRoot;
+ if(pstrBack == NULL)
+ pstrBack = m_lpszRoot;
+
+ // from the start to the last whack is the root
+
+ if(pstrFront >= pstrBack)
+ *pstrFront = _T('\0');
+ else
+ *pstrBack = _T('\0');
+ }
+ }
+
+ m_bFound = TRUE;
+
+ return TRUE;
+ }
+
+ BOOL FindNextFile()
+ {
+ ATLASSERT(m_hFind != NULL);
+
+ if(m_hFind == NULL)
+ return FALSE;
+
+ if(!m_bFound)
+ return FALSE;
+
+ m_bFound = ::FindNextFile(m_hFind, &m_fd);
+
+ return m_bFound;
+ }
+
+ void Close()
+ {
+ m_bFound = FALSE;
+
+ if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE)
+ {
+ ::FindClose(m_hFind);
+ m_hFind = NULL;
+ }
+ }
+
+// Helper
+ static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
+ {
+#ifdef _ATL_MIN_CRT
+ const TCHAR* lpsz = NULL;
+ while (*p != 0)
+ {
+ if (*p == ch)
+ lpsz = p;
+ p = ::CharNext(p);
+ }
+ return lpsz;
+#else // !_ATL_MIN_CRT
+ return _tcsrchr(p, ch);
+#endif // !_ATL_MIN_CRT
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global functions for stock GDI objects
+
+inline HPEN AtlGetStockPen(int nPen)
+{
+#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
+ ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);
+#else
+ ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);
+#endif
+ return (HPEN)::GetStockObject(nPen);
+}
+
+inline HBRUSH AtlGetStockBrush(int nBrush)
+{
+#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
+ ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);
+#else
+ ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);
+#endif
+ return (HBRUSH)::GetStockObject(nBrush);
+}
+
+inline HFONT AtlGetStockFont(int nFont)
+{
+#ifndef _WIN32_WCE
+ ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);
+#else // CE specific
+ ATLASSERT(nFont == SYSTEM_FONT);
+#endif // _WIN32_WCE
+ return (HFONT)::GetStockObject(nFont);
+}
+
+inline HPALETTE AtlGetStockPalette(int nPalette)
+{
+ ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
+ return (HPALETTE)::GetStockObject(nPalette);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global function for compacting a path by replacing parts with ellipsis
+
+// helper for multi-byte character sets
+inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar)
+{
+#ifndef _UNICODE
+ int i = nChar;
+ for( ; i > 0; i--)
+ {
+ if(!::IsDBCSLeadByte(lpstr[i - 1]))
+ break;
+ }
+ return ((nChar > 0) && (((nChar - i) & 1) != 0));
+#else // _UNICODE
+ lpstr; nChar;
+ return false;
+#endif // _UNICODE
+}
+
+inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
+{
+ ATLASSERT(lpstrOut != NULL);
+ ATLASSERT(lpstrIn != NULL);
+ ATLASSERT(cchLen > 0);
+
+ LPCTSTR szEllipsis = _T("...");
+ const int cchEndEllipsis = 3;
+ const int cchMidEllipsis = 4;
+
+ if(lstrlen(lpstrIn) < cchLen)
+ {
+ SecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn);
+ return true;
+ }
+
+ lpstrOut[0] = 0;
+
+ // check if the separator is a slash or a backslash
+ TCHAR chSlash = _T('\\');
+ for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr))
+ {
+ if((*lpstr == _T('/')) || (*lpstr == _T('\\')))
+ chSlash = *lpstr;
+ }
+
+ // find the filename portion of the path
+ LPCTSTR lpstrFileName = lpstrIn;
+ for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath))
+ {
+ if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _T('/'))
+ && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/'))
+ lpstrFileName = pPath + 1;
+ }
+ int cchFileName = lstrlen(lpstrFileName);
+
+ // handle just the filename without a path
+ if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis)
+ {
+ bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0);
+ if(bRet)
+ {
+#ifndef _UNICODE
+ if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis))
+ lpstrOut[cchLen - cchEndEllipsis - 1] = 0;
+#endif // _UNICODE
+ SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
+ }
+ return bRet;
+ }
+
+ // handle just ellipsis
+ if((cchLen < (cchMidEllipsis + cchEndEllipsis)))
+ {
+ for(int i = 0; i < cchLen - 1; i++)
+ lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.');
+ lpstrOut[cchLen - 1] = 0;
+ return true;
+ }
+
+ // calc how much we have to copy
+ int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1;
+
+ if(cchToCopy < 0)
+ cchToCopy = 0;
+
+#ifndef _UNICODE
+ if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy))
+ cchToCopy--;
+#endif // _UNICODE
+
+ bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0);
+ if(!bRet)
+ return false;
+
+ // add ellipsis
+ SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
+ if(!bRet)
+ return false;
+ TCHAR szSlash[2] = { chSlash, 0 };
+ SecureHelper::strcat_x(lpstrOut, cchLen, szSlash);
+ if(!bRet)
+ return false;
+
+ // add filename (and ellipsis, if needed)
+ if(cchLen > (cchMidEllipsis + cchFileName))
+ {
+ SecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName);
+ }
+ else
+ {
+ cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1;
+#ifndef _UNICODE
+ if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy))
+ cchToCopy--;
+#endif // _UNICODE
+ bRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0);
+ if(bRet)
+ SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
+ }
+
+ return bRet;
+}
+
+}; // namespace WTL
+
+#endif // __ATLMISC_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLPRINT_H__
+#define __ATLPRINT_H__
+
+#pragma once
+
+#ifdef _WIN32_WCE
+ #error atlprint.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLAPP_H__
+ #error atlprint.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlprint.h requires atlwin.h to be included first
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CPrinterInfo<t_nInfo>
+// CPrinterT<t_bManaged>
+// CDevModeT<t_bManaged>
+// CPrinterDC
+// CPrintJobInfo
+// CPrintJob
+// CPrintPreview
+// CPrintPreviewWindowImpl<T, TBase, TWinTraits>
+// CPrintPreviewWindow
+// CZoomPrintPreviewWindowImpl<T, TBase, TWinTraits>
+// CZoomPrintPreviewWindow
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures
+// and provided by ::GetPrinter.
+
+template <unsigned int t_nInfo>
+class _printer_info
+{
+public:
+ typedef void infotype;
+};
+
+template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; };
+template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; };
+template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; };
+template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; };
+template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; };
+template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; };
+template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; };
+// these are not in the old (vc6.0) headers
+#ifdef _ATL_USE_NEW_PRINTER_INFO
+template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; };
+template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; };
+#endif // _ATL_USE_NEW_PRINTER_INFO
+
+
+template <unsigned int t_nInfo>
+class CPrinterInfo
+{
+public:
+// Data members
+ typename _printer_info<t_nInfo>::infotype* m_pi;
+
+// Constructor/destructor
+ CPrinterInfo() : m_pi(NULL)
+ { }
+
+ CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
+ {
+ GetPrinterInfo(hPrinter);
+ }
+
+ ~CPrinterInfo()
+ {
+ Cleanup();
+ }
+
+// Operations
+ bool GetPrinterInfo(HANDLE hPrinter)
+ {
+ Cleanup();
+ return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
+ }
+
+// Implementation
+ void Cleanup()
+ {
+ delete [] (BYTE*)m_pi;
+ m_pi = NULL;
+ }
+
+ static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex)
+ {
+ ATLASSERT(pi != NULL);
+ DWORD dw = 0;
+ BYTE* pb = NULL;
+ ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw);
+ if (dw > 0)
+ {
+ ATLTRY(pb = new BYTE[dw]);
+ if (pb != NULL)
+ {
+ memset(pb, 0, dw);
+ DWORD dwNew;
+ if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew))
+ {
+ delete [] pb;
+ pb = NULL;
+ }
+ }
+ }
+ *pi = pb;
+ return (pb != NULL);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrinter - Wrapper class for a HANDLE to a printer
+
+template <bool t_bManaged>
+class CPrinterT
+{
+public:
+// Data members
+ HANDLE m_hPrinter;
+
+// Constructor/destructor
+ CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
+ { }
+
+ ~CPrinterT()
+ {
+ ClosePrinter();
+ }
+
+// Operations
+ CPrinterT& operator =(HANDLE hPrinter)
+ {
+ if (hPrinter != m_hPrinter)
+ {
+ ClosePrinter();
+ m_hPrinter = hPrinter;
+ }
+ return *this;
+ }
+
+ bool IsNull() const { return (m_hPrinter == NULL); }
+
+ bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL)
+ {
+ bool b = false;
+ DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames);
+ if (pdn != NULL)
+ {
+ LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset;
+ b = OpenPrinter(lpszPrinterName, pDevMode);
+ ::GlobalUnlock(hDevNames);
+ }
+ return b;
+ }
+
+ bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL)
+ {
+ ClosePrinter();
+ PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
+ ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
+
+ return (m_hPrinter != NULL);
+ }
+
+ bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs)
+ {
+ ClosePrinter();
+ ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs);
+ return (m_hPrinter != NULL);
+ }
+
+ bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL)
+ {
+ ClosePrinter();
+ const int cchBuff = 512;
+ TCHAR buffer[cchBuff];
+ buffer[0] = 0;
+ ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff);
+ int nLen = lstrlen(buffer);
+ if (nLen != 0)
+ {
+ LPTSTR lpsz = buffer;
+ while (*lpsz)
+ {
+ if (*lpsz == _T(','))
+ {
+ *lpsz = 0;
+ break;
+ }
+ lpsz = CharNext(lpsz);
+ }
+ PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
+ ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
+ }
+ return m_hPrinter != NULL;
+ }
+
+ void ClosePrinter()
+ {
+ if (m_hPrinter != NULL)
+ {
+ if (t_bManaged)
+ ::ClosePrinter(m_hPrinter);
+ m_hPrinter = NULL;
+ }
+ }
+
+ bool PrinterProperties(HWND hWnd = NULL)
+ {
+ if (hWnd == NULL)
+ hWnd = ::GetActiveWindow();
+ return !!::PrinterProperties(hWnd, m_hPrinter);
+ }
+
+ HANDLE CopyToHDEVNAMES() const
+ {
+ HANDLE h = NULL;
+ CPrinterInfo<5> pinfon5;
+ CPrinterInfo<2> pinfon2;
+ LPTSTR lpszPrinterName = NULL;
+ // Some printers fail for PRINTER_INFO_5 in some situations
+ if (pinfon5.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfon5.m_pi->pPrinterName;
+ else if (pinfon2.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfon2.m_pi->pPrinterName;
+ if (lpszPrinterName != NULL)
+ {
+ int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR);
+ h = ::GlobalAlloc(GMEM_MOVEABLE, nLen);
+ BYTE* pv = (BYTE*)::GlobalLock(h);
+ DEVNAMES* pdev = (DEVNAMES*)pv;
+ if (pv != NULL)
+ {
+ memset(pv, 0, nLen);
+ pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
+ pv = pv + sizeof(DEVNAMES); // now points to end
+ SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName);
+ ::GlobalUnlock(h);
+ }
+ }
+ return h;
+ }
+
+ HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const
+ {
+ CPrinterInfo<5> pinfo5;
+ CPrinterInfo<2> pinfo2;
+ HDC hDC = NULL;
+ LPTSTR lpszPrinterName = NULL;
+ // Some printers fail for PRINTER_INFO_5 in some situations
+ if (pinfo5.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfo5.m_pi->pPrinterName;
+ else if (pinfo2.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfo2.m_pi->pPrinterName;
+ if (lpszPrinterName != NULL)
+ hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm);
+ return hDC;
+ }
+
+ HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const
+ {
+ CPrinterInfo<5> pinfo5;
+ CPrinterInfo<2> pinfo2;
+ HDC hDC = NULL;
+ LPTSTR lpszPrinterName = NULL;
+ // Some printers fail for PRINTER_INFO_5 in some situations
+ if (pinfo5.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfo5.m_pi->pPrinterName;
+ else if (pinfo2.GetPrinterInfo(m_hPrinter))
+ lpszPrinterName = pinfo2.m_pi->pPrinterName;
+ if (lpszPrinterName != NULL)
+ hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm);
+ return hDC;
+ }
+
+ void Attach(HANDLE hPrinter)
+ {
+ ClosePrinter();
+ m_hPrinter = hPrinter;
+ }
+
+ HANDLE Detach()
+ {
+ HANDLE hPrinter = m_hPrinter;
+ m_hPrinter = NULL;
+ return hPrinter;
+ }
+
+ operator HANDLE() const { return m_hPrinter; }
+};
+
+typedef CPrinterT<false> CPrinterHandle;
+typedef CPrinterT<true> CPrinter;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CDevMode - Wrapper class for DEVMODE
+
+template <bool t_bManaged>
+class CDevModeT
+{
+public:
+// Data members
+ HANDLE m_hDevMode;
+ DEVMODE* m_pDevMode;
+
+// Constructor/destructor
+ CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode)
+ {
+ m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;
+ }
+
+ ~CDevModeT()
+ {
+ Cleanup();
+ }
+
+// Operations
+ CDevModeT<t_bManaged>& operator =(HANDLE hDevMode)
+ {
+ Attach(hDevMode);
+ return *this;
+ }
+
+ void Attach(HANDLE hDevModeNew)
+ {
+ Cleanup();
+ m_hDevMode = hDevModeNew;
+ m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;
+ }
+
+ HANDLE Detach()
+ {
+ if (m_hDevMode != NULL)
+ ::GlobalUnlock(m_hDevMode);
+ HANDLE hDevMode = m_hDevMode;
+ m_hDevMode = NULL;
+ return hDevMode;
+ }
+
+ bool IsNull() const { return (m_hDevMode == NULL); }
+
+ bool CopyFromPrinter(HANDLE hPrinter)
+ {
+ CPrinterInfo<2> pinfo;
+ bool b = pinfo.GetPrinterInfo(hPrinter);
+ if (b)
+ b = CopyFromDEVMODE(pinfo.m_pi->pDevMode);
+ return b;
+ }
+
+ bool CopyFromDEVMODE(const DEVMODE* pdm)
+ {
+ if (pdm == NULL)
+ return false;
+ int nSize = pdm->dmSize + pdm->dmDriverExtra;
+ HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);
+ if (h != NULL)
+ {
+ void* p = ::GlobalLock(h);
+ SecureHelper::memcpy_x(p, nSize, pdm, nSize);
+ ::GlobalUnlock(h);
+ }
+ Attach(h);
+ return (h != NULL);
+ }
+
+ bool CopyFromHDEVMODE(HANDLE hdm)
+ {
+ bool b = false;
+ if (hdm != NULL)
+ {
+ DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm);
+ b = CopyFromDEVMODE(pdm);
+ ::GlobalUnlock(hdm);
+ }
+ return b;
+ }
+
+ HANDLE CopyToHDEVMODE()
+ {
+ if ((m_hDevMode == NULL) || (m_pDevMode == NULL))
+ return NULL;
+ int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra;
+ HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);
+ if (h != NULL)
+ {
+ void* p = ::GlobalLock(h);
+ SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize);
+ ::GlobalUnlock(h);
+ }
+ return h;
+ }
+
+ // If this devmode was for another printer, this will create a new devmode
+ // based on the existing devmode, but retargeted at the new printer
+ bool UpdateForNewPrinter(HANDLE hPrinter)
+ {
+ bool bRet = false;
+ LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0);
+ CTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ DEVMODE* pdm = buff.AllocateBytes(nLen);
+ if(pdm != NULL)
+ {
+ memset(pdm, 0, nLen);
+ LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
+ if (l == IDOK)
+ bRet = CopyFromDEVMODE(pdm);
+ }
+
+ return bRet;
+ }
+
+ bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL)
+ {
+ CPrinterInfo<1> pi;
+ pi.GetPrinterInfo(hPrinter);
+ if (hWnd == NULL)
+ hWnd = ::GetActiveWindow();
+
+ bool bRet = false;
+ LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0);
+ CTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ DEVMODE* pdm = buff.AllocateBytes(nLen);
+ if(pdm != NULL)
+ {
+ memset(pdm, 0, nLen);
+ LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT);
+ if (l == IDOK)
+ bRet = CopyFromDEVMODE(pdm);
+ }
+
+ return bRet;
+ }
+
+ operator HANDLE() const { return m_hDevMode; }
+
+ operator DEVMODE*() const { return m_pDevMode; }
+
+// Implementation
+ void Cleanup()
+ {
+ if (m_hDevMode != NULL)
+ {
+ ::GlobalUnlock(m_hDevMode);
+ if(t_bManaged)
+ ::GlobalFree(m_hDevMode);
+ m_hDevMode = NULL;
+ }
+ }
+};
+
+typedef CDevModeT<false> CDevModeHandle;
+typedef CDevModeT<true> CDevMode;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrinterDC
+
+class CPrinterDC : public CDC
+{
+public:
+// Constructors/destructor
+ CPrinterDC()
+ {
+ CPrinter printer;
+ printer.OpenDefaultPrinter();
+ Attach(printer.CreatePrinterDC());
+ ATLASSERT(m_hDC != NULL);
+ }
+
+ CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL)
+ {
+ CPrinterHandle p;
+ p.Attach(hPrinter);
+ Attach(p.CreatePrinterDC(pdm));
+ ATLASSERT(m_hDC != NULL);
+ }
+
+ ~CPrinterDC()
+ {
+ DeleteDC();
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc)
+// Handles aborting, background printing
+
+// Defines callbacks used by CPrintJob (not a COM interface)
+class ATL_NO_VTABLE IPrintJobInfo
+{
+public:
+ virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc.
+ virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc.
+ virtual void PrePrintPage(UINT nPage, HDC hDC) = 0;
+ virtual bool PrintPage(UINT nPage, HDC hDC) = 0;
+ virtual void PostPrintPage(UINT nPage, HDC hDC) = 0;
+ // If you want per page devmodes, return the DEVMODE* to use for nPage.
+ // You can optimize by only returning a new DEVMODE* when it is different
+ // from the one for nLastPage, otherwise return NULL.
+ // When nLastPage==0, the current DEVMODE* will be the default passed to
+ // StartPrintJob.
+ // Note: During print preview, nLastPage will always be "0".
+ virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0;
+ virtual bool IsValidPage(UINT nPage) = 0;
+};
+
+// Provides a default implementatin for IPrintJobInfo
+// Typically, MI'd into a document or view class
+class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo
+{
+public:
+ virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc
+ {
+ }
+
+ virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc
+ {
+ }
+
+ virtual void PrePrintPage(UINT /*nPage*/, HDC hDC)
+ {
+ m_nPJState = ::SaveDC(hDC);
+ }
+
+ virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0;
+
+ virtual void PostPrintPage(UINT /*nPage*/, HDC hDC)
+ {
+ RestoreDC(hDC, m_nPJState);
+ }
+
+ virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)
+ {
+ return NULL;
+ }
+
+ virtual bool IsValidPage(UINT /*nPage*/)
+ {
+ return true;
+ }
+
+// Implementation - data
+ int m_nPJState;
+};
+
+
+class CPrintJob
+{
+public:
+// Data members
+ CPrinterHandle m_printer;
+ IPrintJobInfo* m_pInfo;
+ DEVMODE* m_pDefDevMode;
+ DOCINFO m_docinfo;
+ int m_nJobID;
+ bool m_bCancel;
+ bool m_bComplete;
+ unsigned long m_nStartPage;
+ unsigned long m_nEndPage;
+
+// Constructor/destructor
+ CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true)
+ { }
+
+ ~CPrintJob()
+ {
+ ATLASSERT(IsJobComplete()); // premature destruction?
+ }
+
+// Operations
+ bool IsJobComplete() const
+ {
+ return m_bComplete;
+ }
+
+ bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode,
+ IPrintJobInfo* pInfo, LPCTSTR lpszDocName,
+ unsigned long nStartPage, unsigned long nEndPage,
+ bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL)
+ {
+ ATLASSERT(m_bComplete); // previous job not done yet?
+ if (pInfo == NULL)
+ return false;
+
+ memset(&m_docinfo, 0, sizeof(m_docinfo));
+ m_docinfo.cbSize = sizeof(m_docinfo);
+ m_docinfo.lpszDocName = lpszDocName;
+ m_pInfo = pInfo;
+ m_nStartPage = nStartPage;
+ m_nEndPage = nEndPage;
+ m_printer.Attach(hPrinter);
+ m_pDefDevMode = pDefaultDevMode;
+ m_bComplete = false;
+
+ if(bPrintToFile)
+ m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:");
+
+ if (!bBackground)
+ {
+ m_bComplete = true;
+ return StartHelper();
+ }
+
+ // Create a thread and return
+ DWORD dwThreadID = 0;
+#if !defined(_ATL_MIN_CRT) && defined(_MT)
+ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID);
+#else
+ HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID);
+#endif
+ if (hThread == NULL)
+ return false;
+
+ ::CloseHandle(hThread);
+
+ return true;
+ }
+
+// Implementation
+ static DWORD WINAPI StartProc(void* p)
+ {
+ CPrintJob* pThis = (CPrintJob*)p;
+ pThis->StartHelper();
+ pThis->m_bComplete = true;
+ return 0;
+ }
+
+ bool StartHelper()
+ {
+ CDC dcPrinter;
+ dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode));
+ if (dcPrinter.IsNull())
+ return false;
+
+ m_nJobID = ::StartDoc(dcPrinter, &m_docinfo);
+ if (m_nJobID <= 0)
+ return false;
+
+ m_pInfo->BeginPrintJob(dcPrinter);
+
+ // print all the pages now
+ unsigned long nLastPage = 0;
+ for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++)
+ {
+ if (!m_pInfo->IsValidPage(nPage))
+ break;
+ DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage);
+ if (pdm != NULL)
+ dcPrinter.ResetDC(pdm);
+ dcPrinter.StartPage();
+ m_pInfo->PrePrintPage(nPage, dcPrinter);
+ if (!m_pInfo->PrintPage(nPage, dcPrinter))
+ m_bCancel = true;
+ m_pInfo->PostPrintPage(nPage, dcPrinter);
+ dcPrinter.EndPage();
+ if (m_bCancel)
+ break;
+ nLastPage = nPage;
+ }
+
+ m_pInfo->EndPrintJob(dcPrinter, m_bCancel);
+ if (m_bCancel)
+ ::AbortDoc(dcPrinter);
+ else
+ ::EndDoc(dcPrinter);
+ m_nJobID = 0;
+ return true;
+ }
+
+ // Cancels a print job. Can be called asynchronously.
+ void CancelPrintJob()
+ {
+ m_bCancel = true;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrintPreview - Adds print preview support to an existing window
+
+class CPrintPreview
+{
+public:
+// Data members
+ IPrintJobInfo* m_pInfo;
+ CPrinterHandle m_printer;
+ CEnhMetaFile m_meta;
+ DEVMODE* m_pDefDevMode;
+ DEVMODE* m_pCurDevMode;
+ SIZE m_sizeCurPhysOffset;
+
+// Constructor
+ CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL)
+ {
+ m_sizeCurPhysOffset.cx = 0;
+ m_sizeCurPhysOffset.cy = 0;
+ }
+
+// Operations
+ void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji)
+ {
+ m_printer.Attach(hPrinter);
+ m_pDefDevMode = pDefaultDevMode;
+ m_pInfo = pji;
+ m_nCurPage = 0;
+ m_pCurDevMode = NULL;
+ }
+
+ void SetEnhMetaFile(HENHMETAFILE hEMF)
+ {
+ m_meta = hEMF;
+ }
+
+ void SetPage(int nPage)
+ {
+ if (!m_pInfo->IsValidPage(nPage))
+ return;
+ m_nCurPage = nPage;
+ m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage);
+ if (m_pCurDevMode == NULL)
+ m_pCurDevMode = m_pDefDevMode;
+ CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode);
+
+ int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH);
+ int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT);
+ int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX);
+ int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY);
+
+ RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) };
+
+ m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX);
+ m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY);
+
+ CEnhMetaFileDC dcMeta(dcPrinter, &rcMM);
+ m_pInfo->PrePrintPage(nPage, dcMeta);
+ m_pInfo->PrintPage(nPage, dcMeta);
+ m_pInfo->PostPrintPage(nPage, dcMeta);
+ m_meta.Attach(dcMeta.Close());
+ }
+
+ void GetPageRect(RECT& rc, LPRECT prc)
+ {
+ int x1 = rc.right-rc.left;
+ int y1 = rc.bottom - rc.top;
+ if ((x1 < 0) || (y1 < 0))
+ return;
+
+ CEnhMetaFileInfo emfinfo(m_meta);
+ ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
+
+ // Compute whether we are OK vertically or horizontally
+ int x2 = pmh->szlDevice.cx;
+ int y2 = pmh->szlDevice.cy;
+ int y1p = MulDiv(x1, y2, x2);
+ int x1p = MulDiv(y1, x2, y2);
+ ATLASSERT((x1p <= x1) || (y1p <= y1));
+ if (x1p <= x1)
+ {
+ prc->left = rc.left + (x1 - x1p) / 2;
+ prc->right = prc->left + x1p;
+ prc->top = rc.top;
+ prc->bottom = rc.bottom;
+ }
+ else
+ {
+ prc->left = rc.left;
+ prc->right = rc.right;
+ prc->top = rc.top + (y1 - y1p) / 2;
+ prc->bottom = prc->top + y1p;
+ }
+ }
+
+// Painting helpers
+ void DoPaint(CDCHandle dc)
+ {
+ // this one is not used
+ }
+
+ void DoPaint(CDCHandle dc, RECT& rc)
+ {
+ CEnhMetaFileInfo emfinfo(m_meta);
+ ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
+ int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
+ int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
+
+ dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
+ dc.PlayMetaFile(m_meta, &rc);
+ }
+
+// Implementation - data
+ int m_nCurPage;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CPrintPreviewWindow - Implements a print preview window
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CPrintPreview
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1)
+
+ enum { m_cxOffset = 10, m_cyOffset = 10 };
+
+// Constructor
+ CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0)
+ { }
+
+// Operations
+ void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode,
+ IPrintJobInfo* pji, int nMinPage, int nMaxPage)
+ {
+ CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji);
+ m_nMinPage = nMinPage;
+ m_nMaxPage = nMaxPage;
+ }
+
+ bool NextPage()
+ {
+ if (m_nCurPage == m_nMaxPage)
+ return false;
+ SetPage(m_nCurPage + 1);
+ Invalidate();
+ return true;
+ }
+
+ bool PrevPage()
+ {
+ if (m_nCurPage == m_nMinPage)
+ return false;
+ if (m_nCurPage == 0)
+ return false;
+ SetPage(m_nCurPage - 1);
+ Invalidate();
+ return true;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CPrintPreviewWindowImpl)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ END_MSG_MAP()
+
+ LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no need for the background
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rc = { 0 };
+
+ if(wParam != NULL)
+ {
+ pT->DoPrePaint((HDC)wParam, rc);
+ pT->DoPaint((HDC)wParam, rc);
+ }
+ else
+ {
+ CPaintDC dc(m_hWnd);
+ pT->DoPrePaint(dc.m_hDC, rc);
+ pT->DoPaint(dc.m_hDC, rc);
+ }
+
+ return 0;
+ }
+
+// Painting helper
+ void DoPrePaint(CDCHandle dc, RECT& rc)
+ {
+ RECT rcClient = { 0 };
+ GetClientRect(&rcClient);
+ RECT rcArea = rcClient;
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
+ if (rcArea.left > rcArea.right)
+ rcArea.right = rcArea.left;
+ if (rcArea.top > rcArea.bottom)
+ rcArea.bottom = rcArea.top;
+ GetPageRect(rcArea, &rc);
+ CRgn rgn1, rgn2;
+ rgn1.CreateRectRgnIndirect(&rc);
+ rgn2.CreateRectRgnIndirect(&rcClient);
+ rgn2.CombineRgn(rgn1, RGN_DIFF);
+ dc.SelectClipRgn(rgn2);
+ dc.FillRect(&rcClient, COLOR_BTNSHADOW);
+ dc.SelectClipRgn(NULL);
+ dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH));
+ }
+
+// Implementation - data
+ int m_nMinPage;
+ int m_nMaxPage;
+};
+
+
+class CPrintPreviewWindow : public CPrintPreviewWindowImpl<CPrintPreviewWindow>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CZoomPrintPreviewWindowImpl - Implements print preview window with zooming
+
+#ifdef __ATLSCRL_H__
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >
+{
+public:
+ bool m_bSized;
+
+ CZoomPrintPreviewWindowImpl()
+ {
+ SetScrollExtendedStyle(SCRL_DISABLENOSCROLL);
+ InitZoom();
+ }
+
+ // should be called to reset data members before recreating window
+ void InitZoom()
+ {
+ m_bSized = false;
+ m_nZoomMode = ZOOMMODE_OFF;
+ m_fZoomScaleMin = 1.0;
+ m_fZoomScale = 1.0;
+ }
+
+ BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl)
+ MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
+ MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ POINT ptOffset = m_ptOffset;
+ SIZE sizeAll = m_sizeAll;
+ SetScrollSize(sizeClient);
+ if(sizeAll.cx > 0)
+ ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx);
+ if(sizeAll.cy > 0)
+ ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy);
+ SetScrollOffset(ptOffset);
+ CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled);
+ if(!m_bSized)
+ {
+ m_bSized = true;
+ T* pT = static_cast<T*>(this);
+ pT->ShowScrollBar(SB_HORZ, TRUE);
+ pT->ShowScrollBar(SB_VERT, TRUE);
+ }
+ return 0;
+ }
+
+ LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1;
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rc = { 0 };
+
+ if(wParam != NULL)
+ {
+ CDCHandle dc = (HDC)wParam;
+ int nMapModeSav = dc.GetMapMode();
+ dc.SetMapMode(MM_ANISOTROPIC);
+ SIZE szWindowExt = { 0, 0 };
+ dc.SetWindowExt(m_sizeLogAll, &szWindowExt);
+ SIZE szViewportExt = { 0, 0 };
+ dc.SetViewportExt(m_sizeAll, &szViewportExt);
+ POINT ptViewportOrg = { 0, 0 };
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
+
+ pT->DoPrePaint(dc, rc);
+ pT->DoPaint(dc, rc);
+
+ dc.SetMapMode(nMapModeSav);
+ dc.SetWindowExt(szWindowExt);
+ dc.SetViewportExt(szViewportExt);
+ dc.SetViewportOrg(ptViewportOrg);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ pT->PrepareDC(dc.m_hDC);
+ pT->DoPrePaint(dc.m_hDC, rc);
+ pT->DoPaint(dc.m_hDC, rc);
+ }
+
+ return 0;
+ }
+
+ // Painting helpers
+ void DoPaint(CDCHandle dc)
+ {
+ // this one is not used
+ }
+
+ void DoPrePaint(CDCHandle dc, RECT& rc)
+ {
+ RECT rcClient;
+ GetClientRect(&rcClient);
+ RECT rcArea = rcClient;
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
+ if (rcArea.left > rcArea.right)
+ rcArea.right = rcArea.left;
+ if (rcArea.top > rcArea.bottom)
+ rcArea.bottom = rcArea.top;
+ GetPageRect(rcArea, &rc);
+ HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
+ dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY);
+ dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY);
+ dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY);
+ dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY);
+ dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH));
+ dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
+ dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW));
+ dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY);
+ dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY);
+ dc.SelectBrush(hbrOld);
+ }
+
+ void DoPaint(CDCHandle dc, RECT& rc)
+ {
+ CEnhMetaFileInfo emfinfo(m_meta);
+ ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
+ int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
+ int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
+
+ dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
+ dc.PlayMetaFile(m_meta, &rc);
+ }
+};
+
+class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl<CZoomPrintPreviewWindow>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
+};
+
+#endif // __ATLSCRL_H__
+
+}; // namespace WTL
+
+#endif // __ATLPRINT_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLRES_H__
+#define __ATLRES_H__
+
+#pragma once
+
+#if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__)
+ #error Use atlresCE.h instead of atlres.h for Windows CE
+#endif
+
+
+#ifdef RC_INVOKED
+#ifndef _INC_WINDOWS
+
+ #define _INC_WINDOWS
+
+ #ifndef _WIN32_WCE
+ #define VS_VERSION_INFO 1
+
+ #ifdef APSTUDIO_INVOKED
+ #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols
+ #endif // APSTUDIO_INVOKED
+
+ #ifndef WINVER
+ #define WINVER 0x0400 // default to Windows Version 4.0
+ #endif // !WINVER
+
+ #include <winresrc.h>
+
+ // operation messages sent to DLGINIT
+ #define LB_ADDSTRING (WM_USER+1)
+ #define CB_ADDSTRING (WM_USER+3)
+ #endif // !_WIN32_WCE
+
+ #ifdef APSTUDIO_INVOKED
+ #undef APSTUDIO_HIDDEN_SYMBOLS
+ #endif // APSTUDIO_INVOKED
+
+ #ifdef IDC_STATIC
+ #undef IDC_STATIC
+ #endif // IDC_STATIC
+ #define IDC_STATIC (-1)
+
+#endif // !_INC_WINDOWS
+#endif // RC_INVOKED
+
+#ifdef APSTUDIO_INVOKED
+ #define APSTUDIO_HIDDEN_SYMBOLS
+#endif // APSTUDIO_INVOKED
+
+///////////////////////////////////////////////////////////////////////////////
+// ATL resource types
+
+#ifndef RC_INVOKED
+ #define RT_DLGINIT MAKEINTRESOURCE(240)
+ #define RT_TOOLBAR MAKEINTRESOURCE(241)
+#endif // RC_INVOKED
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef APSTUDIO_INVOKED
+ #undef APSTUDIO_HIDDEN_SYMBOLS
+#endif // APSTUDIO_INVOKED
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard window components
+
+#define ID_SEPARATOR 0 // special separator value
+#define ID_DEFAULT_PANE 0 // default status bar pane
+
+#ifndef RC_INVOKED // code only
+// standard control bars (IDW = window ID)
+ #define ATL_IDW_TOOLBAR 0xE800 // main Toolbar for window
+ #define ATL_IDW_STATUS_BAR 0xE801 // Status bar window
+ #define ATL_IDW_COMMAND_BAR 0xE802 // Command bar window
+
+// parts of a frame window
+ #define ATL_IDW_CLIENT 0xE900
+ #define ATL_IDW_PANE_FIRST 0xE900 // first pane (256 max)
+ #define ATL_IDW_PANE_LAST 0xE9FF
+ #define ATL_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max)
+ #define ATL_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max)
+
+ #define ATL_IDW_SIZE_BOX 0xEA20 // size box for splitters
+ #define ATL_IDW_PANE_SAVE 0xEA21 // to shift ATL_IDW_PANE_FIRST
+
+// bands for a rebar
+ #define ATL_IDW_BAND_FIRST 0xEB00
+ #define ATL_IDW_BAND_LAST 0xEBFF
+#endif // !RC_INVOKED
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard Commands
+
+// File commands
+#define ID_FILE_NEW 0xE100
+#define ID_FILE_OPEN 0xE101
+#define ID_FILE_CLOSE 0xE102
+#define ID_FILE_SAVE 0xE103
+#define ID_FILE_SAVE_AS 0xE104
+#define ID_FILE_PAGE_SETUP 0xE105
+#define ID_FILE_PRINT_SETUP 0xE106
+#define ID_FILE_PRINT 0xE107
+#define ID_FILE_PRINT_DIRECT 0xE108
+#define ID_FILE_PRINT_PREVIEW 0xE109
+#define ID_FILE_UPDATE 0xE10A
+#define ID_FILE_SAVE_COPY_AS 0xE10B
+#define ID_FILE_SEND_MAIL 0xE10C
+
+#define ID_FILE_MRU_FIRST 0xE110
+#define ID_FILE_MRU_FILE1 0xE110 // range - 16 max
+#define ID_FILE_MRU_FILE2 0xE111
+#define ID_FILE_MRU_FILE3 0xE112
+#define ID_FILE_MRU_FILE4 0xE113
+#define ID_FILE_MRU_FILE5 0xE114
+#define ID_FILE_MRU_FILE6 0xE115
+#define ID_FILE_MRU_FILE7 0xE116
+#define ID_FILE_MRU_FILE8 0xE117
+#define ID_FILE_MRU_FILE9 0xE118
+#define ID_FILE_MRU_FILE10 0xE119
+#define ID_FILE_MRU_FILE11 0xE11A
+#define ID_FILE_MRU_FILE12 0xE11B
+#define ID_FILE_MRU_FILE13 0xE11C
+#define ID_FILE_MRU_FILE14 0xE11D
+#define ID_FILE_MRU_FILE15 0xE11E
+#define ID_FILE_MRU_FILE16 0xE11F
+#define ID_FILE_MRU_LAST 0xE11F
+
+// Edit commands
+#define ID_EDIT_CLEAR 0xE120
+#define ID_EDIT_CLEAR_ALL 0xE121
+#define ID_EDIT_COPY 0xE122
+#define ID_EDIT_CUT 0xE123
+#define ID_EDIT_FIND 0xE124
+#define ID_EDIT_PASTE 0xE125
+#define ID_EDIT_PASTE_LINK 0xE126
+#define ID_EDIT_PASTE_SPECIAL 0xE127
+#define ID_EDIT_REPEAT 0xE128
+#define ID_EDIT_REPLACE 0xE129
+#define ID_EDIT_SELECT_ALL 0xE12A
+#define ID_EDIT_UNDO 0xE12B
+#define ID_EDIT_REDO 0xE12C
+
+// Window commands
+#define ID_WINDOW_NEW 0xE130
+#define ID_WINDOW_ARRANGE 0xE131
+#define ID_WINDOW_CASCADE 0xE132
+#define ID_WINDOW_TILE_HORZ 0xE133
+#define ID_WINDOW_TILE_VERT 0xE134
+#define ID_WINDOW_SPLIT 0xE135
+#ifndef RC_INVOKED // code only
+ #define ATL_IDM_WINDOW_FIRST 0xE130
+ #define ATL_IDM_WINDOW_LAST 0xE13F
+ #define ATL_IDM_FIRST_MDICHILD 0xFF00 // window list starts here
+ #define ATL_IDM_LAST_MDICHILD 0xFFFD
+#endif // !RC_INVOKED
+// TabView
+#define ID_WINDOW_TABFIRST 0xFF00 // = ATL_IDM_FIRST_MDICHILD
+#define ID_WINDOW_TABLAST 0xFFFD
+#define ID_WINDOW_SHOWTABLIST 0xFFFE
+
+// Help and App commands
+#define ID_APP_ABOUT 0xE140
+#define ID_APP_EXIT 0xE141
+#define ID_HELP_INDEX 0xE142
+#define ID_HELP_FINDER 0xE143
+#define ID_HELP_USING 0xE144
+#define ID_CONTEXT_HELP 0xE145 // shift-F1
+// special commands for processing help
+#define ID_HELP 0xE146 // first attempt for F1
+#define ID_DEFAULT_HELP 0xE147 // last attempt
+
+// Misc
+#define ID_NEXT_PANE 0xE150
+#define ID_PREV_PANE 0xE151
+#define ID_PANE_CLOSE 0xE152
+
+// Format
+#define ID_FORMAT_FONT 0xE160
+
+// Scroll
+#define ID_SCROLL_UP 0xE170
+#define ID_SCROLL_DOWN 0xE171
+#define ID_SCROLL_PAGE_UP 0xE172
+#define ID_SCROLL_PAGE_DOWN 0xE173
+#define ID_SCROLL_TOP 0xE174
+#define ID_SCROLL_BOTTOM 0xE175
+#define ID_SCROLL_LEFT 0xE176
+#define ID_SCROLL_RIGHT 0xE177
+#define ID_SCROLL_PAGE_LEFT 0xE178
+#define ID_SCROLL_PAGE_RIGHT 0xE179
+#define ID_SCROLL_ALL_LEFT 0xE17A
+#define ID_SCROLL_ALL_RIGHT 0xE17B
+
+// OLE commands
+#define ID_OLE_INSERT_NEW 0xE200
+#define ID_OLE_EDIT_LINKS 0xE201
+#define ID_OLE_EDIT_CONVERT 0xE202
+#define ID_OLE_EDIT_CHANGE_ICON 0xE203
+#define ID_OLE_EDIT_PROPERTIES 0xE204
+#define ID_OLE_VERB_FIRST 0xE210 // range - 16 max
+#ifndef RC_INVOKED // code only
+ #define ID_OLE_VERB_LAST 0xE21F
+#endif // !RC_INVOKED
+
+// View commands (same number used as IDW used for toolbar and status bar)
+#define ID_VIEW_TOOLBAR 0xE800
+#define ID_VIEW_STATUS_BAR 0xE801
+#define ID_VIEW_REFRESH 0xE803
+#define ID_VIEW_RIBBON 0xE804 // Ribbon
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard control IDs
+
+#ifdef IDC_STATIC
+ #undef IDC_STATIC
+#endif // IDC_STATIC
+#define IDC_STATIC (-1) // all static controls
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard string error/warnings
+
+// idle status bar message
+#define ATL_IDS_IDLEMESSAGE 0xE001
+
+#ifndef RC_INVOKED // code only
+ #define ATL_IDS_SCFIRST 0xEF00
+#endif // !RC_INVOKED
+
+#define ATL_IDS_SCSIZE 0xEF00
+#define ATL_IDS_SCMOVE 0xEF01
+#define ATL_IDS_SCMINIMIZE 0xEF02
+#define ATL_IDS_SCMAXIMIZE 0xEF03
+#define ATL_IDS_SCNEXTWINDOW 0xEF04
+#define ATL_IDS_SCPREVWINDOW 0xEF05
+#define ATL_IDS_SCCLOSE 0xEF06
+#define ATL_IDS_SCRESTORE 0xEF12
+#define ATL_IDS_SCTASKLIST 0xEF13
+
+#define ATL_IDS_MDICHILD 0xEF1F
+#define ATL_IDS_MRU_FILE 0xEFDA
+
+///////////////////////////////////////////////////////////////////////////////
+// Misc. control IDs
+
+// Property Sheet control id's (determined with Spy++)
+#define ID_APPLY_NOW 0x3021
+#define ID_WIZBACK 0x3023
+#define ID_WIZNEXT 0x3024
+#define ID_WIZFINISH 0x3025
+#define ATL_IDC_TAB_CONTROL 0x3020
+
+#endif // __ATLRES_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLRESCE_H__
+#define __ATLRESCE_H__
+
+#pragma once
+
+#ifndef _WIN32_WCE
+ #error atlresCE.h is only for Windows CE
+#endif
+
+
+#ifdef RC_INVOKED
+#ifndef _INC_WINDOWS
+
+ #define VS_VERSION_INFO 1
+
+ #ifdef APSTUDIO_INVOKED
+ #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols
+ #endif // APSTUDIO_INVOKED
+
+ #ifndef WINVER
+ #define WINVER 0x0400 // default to Windows Version 4.0
+ #endif // !WINVER
+
+ #if !defined(WCEOLE_ENABLE_DIALOGEX)
+ #define DIALOGEX DIALOG DISCARDABLE
+ #endif
+
+ #include <commctrl.h>
+ #define SHMENUBAR RCDATA
+
+ #if defined(SHELLSDK_MODULES_AYGSHELL)
+ #include <aygshell.h>
+ #else
+ #define NOMENU 0xFFFF
+ #define IDS_SHNEW 1
+ #define IDM_SHAREDNEW 10
+ #define IDM_SHAREDNEWDEFAULT 11
+ #endif
+ #ifndef I_IMAGENONE
+ #define I_IMAGENONE (-2)
+ #endif
+
+ #include <windows.h>
+
+#endif // !_INC_WINDOWS
+#endif // RC_INVOKED
+
+#include "atlres.h"
+
+#ifdef APSTUDIO_INVOKED
+ #undef APSTUDIO_HIDDEN_SYMBOLS
+#endif // APSTUDIO_INVOKED
+
+// Visual Studio dialog editor bug fix
+#ifndef DS_FIXEDSYS
+ #define DS_FIXEDSYS 0
+#endif
+
+#define IDC_INFOSTATIC 0xFFFE // == IDC_STATIC -1
+
+///////////////////////////////////////////////////////////////////////////////
+// Smartphone and PPC 2005 Resource IDs
+
+// Command and associated string resource IDs
+#define ID_MENU_OK 0xE790
+#define ID_MENU_CANCEL 0xE791
+#define ID_MENU 0xE792
+#define ID_ACTION 0xE793
+#define ID_VIEW_FULLSCREEN 0xE802
+
+// MenuBar resource IDs
+#define ATL_IDM_MENU_DONE 0xE701
+#define ATL_IDM_MENU_CANCEL 0xE702
+#define ATL_IDM_MENU_DONECANCEL 0xE703
+
+// Default device MenuBar control ID and MenuBar resource ID
+#define ATL_IDW_MENU_BAR 0xE802
+
+// SmartPhone spinned controls ID offset for CSpinCtrl
+#define ATL_IDW_SPIN_ID 9999
+
+#endif // __ATLRESCE_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLRIBBON_H__
+#define __ATLRIBBON_H__
+
+#pragma once
+
+#if (_MSC_VER < 1500)
+ #error atlribbon.h requires Visual C++ 2008 compiler or higher
+#endif
+
+#ifndef _UNICODE
+ #error atlribbon.h requires the Unicode character set
+#endif
+
+#if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7)
+ #error atlribbon.h requires the Windows 7 SDK or higher
+#endif
+
+#ifdef _WIN32_WCE
+ #error atlribbon.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLAPP_H__
+ #error atlribbon.h requires atlapp.h to be included first
+#endif
+
+#if (_ATL_VER < 0x0700)
+ #include <shlwapi.h>
+ #pragma comment(lib, "shlwapi.lib")
+#endif
+
+#include <atlmisc.h> // for RecentDocumentList classes
+#include <atlframe.h> // for Frame and UpdateUI classes
+#include <atlctrls.h> // required for atlctrlw.h
+#include <atlctrlw.h> // for CCommandBarCtrl
+
+#if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__)
+ #pragma warning(disable : 4530) // unwind semantics not enabled
+ #include <string>
+ #pragma warning(default : 4530)
+#endif
+
+#include <dwmapi.h>
+#pragma comment(lib, "dwmapi.lib")
+
+#include <UIRibbon.h>
+#include <UIRibbonPropertyHelpers.h>
+#pragma comment(lib, "propsys.lib")
+
+#include <Richedit.h> // for CHARFORMAT2
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CRibbonUpdateUI : Automatic mapping of ribbon UI elements
+//
+// RibbonUI::Text
+// RibbonUI::CharFormat
+// RibbonUI::ICtrl
+// RibbonUI::CtrlImpl
+// RibbonUI::CommandCtrlImpl
+// RibbonUI::ItemProperty
+// RibbonUI::CollectionImplBase
+// RibbonUI::CollectionImpl
+// RibbonUI::TextCollectionImpl
+// RibbonUI::ItemCollectionImpl
+// RibbonUI::ComboCollectionImpl
+// RibbonUI::CommandCollectionImpl
+// RibbonUI::ToolbarCollectionImpl
+// RibbonUI::SimpleCollectionImpl
+// RibbonUI::CollectionCtrlImpl
+// RibbonUI::ToolbarGalleryCtrlImpl
+// RibbonUI::SimpleCollectionCtrlImpl
+// RibbonUI::RecentItemsCtrlImpl
+// RibbonUI::FontCtrlImpl
+// RibbonUI::ColorCtrlImpl
+// RibbonUI::SpinnerCtrlImpl
+//
+// RibbonUI::CRibbonImpl
+// CRibbonImpl::CRibbonComboCtrl
+// CRibbonImpl::CRibbonItemGalleryCtrl
+// CRibbonImpl::CRibbonCommandGalleryCtrl
+// CRibbonImpl::CRibbonToolbarGalleryCtrl
+// CRibbonImpl::CRibbonSimpleComboCtrl
+// CRibbonImpl::CRibbonSimpleGalleryCtrl
+// CRibbonImpl::CRibbonRecentItemsCtrl
+// CRibbonImpl::CRibbonColorCtrl
+// CRibbonImpl::CRibbonFontCtrl
+// CRibbonImpl::CRibbonSpinnerCtrl
+// CRibbonImpl::CRibbonFloatSpinnerCtrl
+// CRibbonImpl::CRibbonCommandCtrl
+//
+// CRibbonFrameWindowImplBase
+// CRibbonFrameWindowImpl
+// CRibbonMDIFrameWindowImpl
+// CRibbonPersist
+//
+// Global functions:
+// RibbonUI::SetPropertyVal()
+// RibbonUI::GetImage()
+
+
+// Constants
+
+#ifndef RIBBONUI_MAX_TEXT
+ #define RIBBONUI_MAX_TEXT 128
+#endif
+
+#define TWIPS_PER_POINT 20 // For font size
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CRibbonUpdateUI : Automatic mapping of ribbon UI elements
+
+template <class T>
+class CRibbonUpdateUI : public CAutoUpdateUI<T>
+{
+public:
+ enum
+ {
+ UPDUI_RIBBON = 0x0080,
+ UPDUI_PERSIST = 0x0020
+ };
+
+ bool IsRibbonElement(const _AtlUpdateUIMap& UIMap)
+ {
+ return (UIMap.m_wType & UPDUI_RIBBON) != 0;
+ }
+
+ bool IsRibbonID(UINT nID)
+ {
+ for(int i = 0; i < m_arrUIMap.GetSize(); i++)
+ {
+ if(m_arrUIMap[i].m_nID == nID)
+ return IsRibbonElement(m_arrUIMap[i]);
+ }
+
+ return false;
+ }
+
+// Element
+ bool UIAddRibbonElement(UINT nID)
+ {
+ return UIAddElement<UPDUI_RIBBON>(nID);
+ }
+
+ bool UIRemoveRibbonElement(UINT nID)
+ {
+ return UIRemoveElement<UPDUI_RIBBON>(nID);
+ }
+
+ bool UIPersistElement(UINT nID, bool bPersist = true)
+ {
+ return bPersist ?
+ UIAddElement<UPDUI_PERSIST>(nID) :
+ UIRemoveElement<UPDUI_PERSIST>(nID);
+ }
+
+// methods for Ribbon elements
+ BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate);
+ if (pT->IsRibbonUI() && IsRibbonID(nID))
+ bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label));
+ return bRes;
+ }
+
+ BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE)
+ {
+ CTempBuffer<WCHAR> sText(RIBBONUI_MAX_TEXT);
+ return AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT) ?
+ UISetText(nID, sText, bForceUpdate) :
+ E_FAIL;
+ }
+
+ LPCTSTR UIGetText(int nID)
+ {
+ T* pT = static_cast<T*>(this);
+ LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID);
+
+ // replace 'tab' by 'space' for RibbonUI elements
+ if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t'))
+ {
+ static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
+ wcscpy_s(sText, sUI);
+ *wcschr(sText, L'\t') = L' ';
+ return sText;
+ }
+ else
+ {
+ return sUI;
+ }
+ }
+
+ BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate);
+ if (pT->IsRibbonUI() && IsRibbonID(nID))
+ bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable));
+ return bRes;
+ }
+
+ BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE)
+ {
+ if ((nCheck == 0) || (nCheck == 1))
+ return UISetCheck(nID, nCheck != 0, bForceUpdate);
+ else
+ return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate);
+ }
+
+ BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
+ {
+ T* pT = static_cast<T*>(this);
+ BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate);
+ if (bRes && pT->IsRibbonUI() && IsRibbonID(nID))
+ bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck));
+ return bRes;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RibbonUI namespace
+//
+
+namespace RibbonUI
+{
+
+// Minimal string allocation support for various PROPERTYKEY values
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ typedef _CSTRING_NS::CString Text;
+#else
+ class Text : public std::wstring
+ {
+ public:
+ Text(std::wstring& s) : std::wstring(s)
+ { }
+ Text(LPCWSTR s) : std::wstring(s)
+ { }
+ Text()
+ { }
+ bool IsEmpty()
+ {
+ return empty();
+ }
+ operator LPCWSTR()
+ {
+ return c_str();
+ }
+ Text& operator =(LPCWSTR s)
+ {
+ return static_cast<Text&>(std::wstring::operator =(s));
+ }
+ };
+#endif
+
+// PROPERTYKEY enum and helpers
+enum k_KEY
+{
+ // state
+ k_Enabled = 1, k_BooleanValue = 200,
+ // text properties
+ k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6,
+ // image properties
+ k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10,
+ // collection properties
+ k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104,
+ // collection item properties
+ k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106,
+ // combo control property
+ k_StringValue = 202,
+ // spinner control properties
+ k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208,
+ // font control properties
+ k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304,
+ k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308,
+ k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312,
+ k_FontProperties_DeltaSize = 313,
+ // recent items properties
+ k_RecentItems = 350, k_Pinned = 351,
+ // color control properties
+ k_Color = 400, k_ColorType = 401, k_ColorMode,
+ k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406,
+ k_NoColorLabel = 407, k_MoreColorsLabel = 408,
+ k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412,
+ // Ribbon state
+ k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100,
+ // Ribbon UI colors
+ k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002
+};
+
+inline k_KEY k_(REFPROPERTYKEY key)
+{
+ return (k_KEY)key.fmtid.Data1;
+}
+
+// PROPERTYKEY value assignment and specializations
+//
+template <typename V>
+HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv)
+{
+ switch (k_(key))
+ {
+ case k_Enabled:
+ case k_BooleanValue:
+ return InitPropVariantFromBoolean(val, ppv);
+ default:
+ return UIInitPropertyFromUInt32(key, val, ppv);
+ }
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv)
+{
+ return SetPropertyVal(key, (LONG)val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv)
+{
+ HRESULT hr = UIInitPropertyFromImage(key, val, ppv);
+ ATLVERIFY(val->Release() == 1);
+ return hr;
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromInterface(key, val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromInterface(key, val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromIUnknownArray(key, val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromDecimal(key, *val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromBoolean(key, val, ppv);
+}
+
+inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv)
+{
+ return UIInitPropertyFromString(key, val, ppv);
+}
+
+// CharFormat helper struct for RibbonUI font control
+//
+struct CharFormat : CHARFORMAT2
+{
+ // Default constructor
+ CharFormat()
+ {
+ cbSize = sizeof CHARFORMAT2;
+ Reset();
+ }
+
+ // Copy constructor
+ CharFormat(const CharFormat& cf)
+ {
+ CopyMemory(this, &cf, sizeof CHARFORMAT2);
+ }
+
+ // Assign operator
+ CharFormat& operator =(const CharFormat& cf)
+ {
+ CopyMemory(this, &cf, sizeof CHARFORMAT2);
+ return (*this);
+ }
+
+ void Reset()
+ {
+ uValue = dwMask = dwEffects = 0;
+ PropVariantInit(&propvar);
+ }
+
+ void operator <<(IPropertyStore* pStore)
+ {
+ if (pStore == NULL)
+ {
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ static void (CharFormat::*Getk_[])(IPropertyStore*) =
+ {
+ &CharFormat::Getk_Family,
+ &CharFormat::Getk_FontProperties_Size,
+ &CharFormat::Getk_MaskEffect<CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold>,
+ &CharFormat::Getk_MaskEffect<CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic>,
+ &CharFormat::Getk_MaskEffect<CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline>,
+ &CharFormat::Getk_MaskEffect<CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough>,
+ &CharFormat::Getk_VerticalPositioning,
+ &CharFormat::Getk_Color<CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor>,
+ &CharFormat::Getk_Color<CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor>,
+ &CharFormat::Getk_ColorType<CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColorType>,
+ &CharFormat::Getk_ColorType<CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColorType>,
+ };
+
+ DWORD nProps = 0;
+ Reset();
+
+ ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps)));
+ for (DWORD iProp = 0; iProp < nProps; iProp++)
+ {
+ PROPERTYKEY key;
+ ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key)));
+ ATLASSERT(k_(key) >= k_FontProperties_Family);
+
+ if (k_(key) <= k_FontProperties_BackgroundColorType)
+ (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore);
+ }
+ }
+
+ void operator >>(IPropertyStore* pStore)
+ {
+ if (pStore == NULL)
+ {
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ PutFace(pStore);
+ PutSize(pStore);
+ PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore);
+ PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore);
+ PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore);
+ PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore);
+ PutVerticalPos(pStore);
+ PutColor(pStore);
+ PutBackColor(pStore);
+ }
+
+private:
+ PROPVARIANT propvar;
+ UINT uValue;
+
+ // Getk_ functions
+ void Getk_Family(IPropertyStore* pStore)
+ {
+ if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar)))
+ {
+ PropVariantToString(propvar, szFaceName, LF_FACESIZE);
+ if (*szFaceName)
+ dwMask |= CFM_FACE;
+ }
+ }
+
+ void Getk_FontProperties_Size(IPropertyStore* pStore)
+ {
+ if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar)))
+ {
+ DECIMAL decSize;
+ UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize);
+ DOUBLE dSize;
+ VarR8FromDec(&decSize, &dSize);
+ if (dSize > 0)
+ {
+ dwMask |= CFM_SIZE;
+ yHeight = (LONG)(dSize * TWIPS_PER_POINT);
+ }
+ }
+ }
+
+ template <DWORD t_dwMask, DWORD t_dwEffects, REFPROPERTYKEY key>
+ void Getk_MaskEffect(IPropertyStore* pStore)
+ {
+ if (SUCCEEDED(pStore->GetValue(key, &propvar)))
+ {
+ UIPropertyToUInt32(key, propvar, &uValue);
+ if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)
+ {
+ dwMask |= t_dwMask;
+ dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0;
+ }
+ }
+ }
+
+ void Getk_VerticalPositioning(IPropertyStore* pStore)
+ {
+ if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar)))
+ {
+ UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue);
+ UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue;
+ if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE))
+ {
+ dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT);
+ if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET)
+ {
+ dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT;
+ }
+ }
+ }
+ }
+
+ template <DWORD t_dwMask, REFPROPERTYKEY key>
+ void Getk_Color(IPropertyStore* pStore)
+ {
+ UINT32 color;
+ if (SUCCEEDED(pStore->GetValue(key, &propvar)))
+ {
+ UIPropertyToUInt32(key, propvar, &color);
+ dwMask |= t_dwMask;
+
+ if (t_dwMask == CFM_COLOR)
+ crTextColor = color;
+ else
+ crBackColor = color;
+ }
+ }
+
+ template <DWORD t_dwMask, DWORD t_dwEffects, UI_SWATCHCOLORTYPE t_type, REFPROPERTYKEY key>
+ void Getk_ColorType(IPropertyStore* pStore)
+ {
+ if (SUCCEEDED(pStore->GetValue(key, &propvar)))
+ {
+ UIPropertyToUInt32(key, propvar, &uValue);
+ if (t_type == (UI_SWATCHCOLORTYPE)uValue)
+ {
+ dwMask |= t_dwMask;
+ dwEffects |= t_dwEffects;
+ }
+ }
+ }
+
+ // Put functions
+ void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore)
+ {
+ PROPVARIANT propvar;
+ UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE;
+ if ((dwMask & dwMaskVal) != 0)
+ uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET;
+ SetPropertyVal(key, uProp, &propvar);
+ pStore->SetValue(key, propvar);
+ }
+
+ void PutVerticalPos(IPropertyStore* pStore)
+ {
+ PROPVARIANT propvar;
+ UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE;
+
+ if ((dwMask & CFE_SUBSCRIPT) != 0)
+ {
+ if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT))
+ uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
+ else
+ uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
+ }
+ else if ((dwMask & CFM_OFFSET) != 0)
+ {
+ if (yOffset > 0)
+ uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
+ else if (yOffset < 0)
+ uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
+ }
+
+ SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, propvar);
+ }
+
+ void PutFace(IPropertyStore* pStore)
+ {
+ PROPVARIANT propvar;
+ SetPropertyVal(UI_PKEY_FontProperties_Family,
+ dwMask & CFM_FACE ? szFaceName : L"", &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_Family, propvar);
+ }
+
+ void PutSize(IPropertyStore* pStore)
+ {
+ PROPVARIANT propvar;
+ DECIMAL decVal;
+
+ if ((dwMask & CFM_SIZE) != 0)
+ VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal);
+ else
+ VarDecFromI4(0, &decVal);
+
+ SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_Size, propvar);
+ }
+
+ void PutColor(IPropertyStore* pStore)
+ {
+ if ((dwMask & CFM_COLOR) != 0)
+ if ((dwEffects & CFE_AUTOCOLOR) == 0)
+ {
+ SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
+
+ SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar);
+ }
+ else
+ {
+ SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
+ }
+ }
+
+ void PutBackColor(IPropertyStore* pStore)
+ {
+ if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0))
+ {
+ SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
+
+ SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar);
+ }
+ else
+ {
+ SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar);
+ pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
+ }
+ }
+};
+
+// IUIImage helper
+//
+inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner)
+{
+ ATLASSERT(hbm);
+ IUIImage* pIUII = NULL;
+ ATL::CComPtr<IUIImageFromBitmap> pIFB;
+
+ if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory))
+ ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII)));
+
+ return pIUII;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Ribbon control classes
+
+// RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes
+//
+struct ICtrl
+{
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* pCommandExecutionProperties) = 0;
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0;
+};
+
+// RibbonUI::CtrlImpl base class for all ribbon controls
+//
+template <class T, UINT t_ID>
+class ATL_NO_VTABLE CtrlImpl : public ICtrl
+{
+protected:
+ T* m_pWndRibbon;
+
+public:
+ typedef T WndRibbon;
+
+ CtrlImpl() : m_pWndRibbon(T::pWndRibbon)
+ { }
+
+ WndRibbon& GetWndRibbon()
+ {
+ return *m_pWndRibbon;
+ }
+
+ static WORD GetID()
+ {
+ return t_ID;
+ }
+
+ Text m_sTxt[5];
+
+ // Operations
+ HRESULT Invalidate()
+ {
+ return GetWndRibbon().InvalidateCtrl(GetID());
+ }
+
+ HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)
+ {
+ return GetWndRibbon().InvalidateProperty(GetID(), key, flags);
+ }
+
+ HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
+
+ m_sTxt[k_(key) - k_LabelDescription] = sTxt;
+
+ return bUpdate ?
+ GetWndRibbon().InvalidateProperty(GetID(), key) :
+ S_OK;
+ }
+
+ // Implementation
+ template <typename V>
+ HRESULT SetProperty(REFPROPERTYKEY key, V val)
+ {
+ return GetWndRibbon().SetProperty(GetID(), key, val);
+ }
+
+ HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv)
+ {
+ ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
+
+ const INT iText = k_(key) - k_LabelDescription;
+ if (m_sTxt[iText].IsEmpty())
+ if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key))
+ m_sTxt[iText] = sText;
+
+ return !m_sTxt[iText].IsEmpty() ?
+ SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) :
+ S_OK;
+ }
+
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* pCommandExecutionProperties)
+ {
+ ATLASSERT(nCmdID == t_ID);
+ return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT(nCmdID == t_ID);
+
+ const INT iMax = k_TooltipTitle - k_LabelDescription;
+ const INT iVal = k_(key) - k_LabelDescription;
+
+ return (iVal <= iMax) && (iVal >= 0) ?
+ OnGetText(key, ppropvarNewValue) :
+ GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ }
+};
+
+// CommandCtrlImpl base class for most ribbon controls
+//
+template <class T, UINT t_ID>
+class CommandCtrlImpl : public CtrlImpl<T, t_ID>
+{
+public:
+ CBitmap m_hbm[4];
+
+ HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
+
+ m_hbm[k_(key) - k_LargeImage].Attach(hbm);
+
+ return bUpdate ?
+ GetWndRibbon().InvalidateProperty(GetID(), key) :
+ S_OK;
+ }
+
+ HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv)
+ {
+ ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
+
+ const INT iImage = k_(key) - k_LargeImage;
+
+ if (m_hbm[iImage].IsNull())
+ m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key);
+
+ return m_hbm[iImage].IsNull() ?
+ E_NOTIMPL :
+ SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv);
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT (nCmdID == GetID());
+
+ return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ?
+ OnGetImage(key, ppropvarNewValue) :
+ CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Ribbon collection base classes
+
+// ItemProperty class: ribbon callback for each item in a collection
+//
+template <class TCollection>
+class ItemProperty : public IUISimplePropertySet
+{
+public:
+ ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection)
+ { }
+
+ const UINT m_Index;
+ TCollection* m_pCollection;
+
+ // IUISimplePropertySet method.
+ STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ return m_pCollection->OnGetItem(m_Index, key, value);
+ }
+
+ // IUnknown methods.
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return 1;
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ return 1;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
+ {
+ if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet)))
+ {
+ *ppv = this;
+ return S_OK;
+ }
+ else
+ {
+ return E_NOINTERFACE;
+ }
+ }
+};
+
+
+// CollectionImplBase: base class for all RibbonUI collections
+//
+template <class TCollection, size_t t_size>
+class CollectionImplBase
+{
+ typedef CollectionImplBase<TCollection, t_size> thisClass;
+
+public:
+ CollectionImplBase()
+ {
+ for (int i = 0; i < t_size; i++)
+ m_apItems[i] = new ItemProperty<TCollection>(i, static_cast<TCollection*>(this));
+ }
+
+ ~CollectionImplBase()
+ {
+ for (int i = 0; i < t_size; i++)
+ delete m_apItems[i];
+ }
+
+// Data members
+ ItemProperty<TCollection>* m_apItems[t_size];
+};
+
+// CollectionImpl: handles categories and collecton resizing
+//
+template <class TCtrl, size_t t_items, size_t t_categories>
+class CollectionImpl : public CollectionImplBase<CollectionImpl<TCtrl, t_items, t_categories>, t_items + t_categories>
+{
+ typedef CollectionImpl<TCtrl, t_items, t_categories> thisClass;
+public:
+ typedef thisClass Collection;
+
+ CollectionImpl() : m_size(t_items)
+ {
+ FillMemory(m_auItemCat, sizeof m_auItemCat, 0xff); // UI_COLLECTION_INVALIDINDEX
+ }
+
+ UINT32 m_auItemCat[t_items];
+ Text m_asCatName[max(t_categories, 1)];
+ size_t m_size;
+
+// Operations
+ HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false)
+ {
+ ATLASSERT((uItem < t_items) && (uCat < t_categories));
+
+ m_auItemCat[uItem] = uCat;
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+ HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false)
+ {
+ ATLASSERT(uCat < t_categories);
+
+ m_asCatName[uCat] = sText;
+
+ return bUpdate ? InvalidateCategories() : S_OK;
+ }
+
+ HRESULT Resize(size_t size, bool bUpdate = false)
+ {
+ ATLASSERT(size <= t_items);
+
+ m_size = size;
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+// Implementation
+ HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uIndex < t_items + t_categories);
+ TCtrl* pCtrl = static_cast<TCtrl*>(this);
+
+ return uIndex < t_items ?
+ pCtrl->DoGetItem(uIndex, key, value) :
+ pCtrl->DoGetCategory(uIndex - t_items, key, value);
+ }
+
+ HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(k_(key) == k_CategoryId);
+ UINT32 uCat = UI_COLLECTION_INVALIDINDEX;
+
+ if (t_categories != 0)
+ {
+ if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX)
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem);
+ }
+ uCat = m_auItemCat[uItem];
+ }
+
+ return SetPropertyVal(key, uCat, value);
+ }
+
+ HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ HRESULT hr = S_OK;
+
+ switch (k_(key))
+ {
+ case k_Label:
+ if (m_asCatName[uCat].IsEmpty())
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat);
+ }
+ hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value);
+ break;
+ case k_CategoryId:
+ hr = SetPropertyVal(key, uCat, value);
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ return hr;
+ }
+
+ HRESULT InvalidateItems()
+ {
+ return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_ItemsSource);
+ }
+
+ HRESULT InvalidateCategories()
+ {
+ return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_Categories);
+ }
+
+ HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/)
+ {
+ ATLASSERT(nCmdID == TCtrl::GetID());
+ nCmdID; // avoid level 4 warning
+
+ HRESULT hr = E_NOTIMPL;
+ switch (k_(key))
+ {
+ case k_ItemsSource:
+ {
+ ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
+ ATLASSERT(pIUICollection);
+ hr = pIUICollection->Clear();
+ for (UINT i = 0; i < m_size; i++)
+ {
+ if FAILED(hr = pIUICollection->Add(m_apItems[i]))
+ break;
+ }
+ ATLASSERT(SUCCEEDED(hr));
+ }
+ break;
+ case k_Categories:
+ if (t_categories != 0)
+ {
+ ATL::CComQIPtr<IUICollection> pIUICategory(ppropvarCurrentValue->punkVal);
+ ATLASSERT(pIUICategory.p);
+ hr = pIUICategory->Clear();
+ for (UINT i = t_items; i < t_items + t_categories; i++)
+ {
+ if FAILED(hr = pIUICategory->Add(m_apItems[i]))
+ break;
+ }
+ ATLASSERT(SUCCEEDED(hr));
+ }
+ break;
+ }
+
+ return hr;
+ }
+};
+
+// TextCollectionImpl: handles item labels and selection
+//
+template <class TCtrl, size_t t_items, size_t t_categories = 0>
+class TextCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
+{
+ typedef TextCollectionImpl<TCtrl, t_items, t_categories> thisClass;
+public:
+ typedef thisClass TextCollection;
+
+ TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX)
+ { }
+
+ Text m_asText[t_items];
+ UINT m_uSelected;
+
+ // Operations
+ HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false)
+ {
+ ATLASSERT(uItem < t_items);
+
+ m_asText[uItem] = sText;
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+ UINT GetSelected()
+ {
+ return m_uSelected;
+ }
+
+ HRESULT Select(UINT uItem, bool bUpdate = false)
+ {
+ ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX));
+
+ m_uSelected = uItem;
+
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ return bUpdate ?
+ ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) :
+ S_OK;
+ }
+
+// Implementation
+ HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uItem < t_items);
+
+ if (k_(key) == k_Label)
+ {
+ if (m_asText[uItem].IsEmpty())
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem);
+ }
+ return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value);
+ }
+ else
+ {
+ return Collection::DoGetItem(uItem, key, value);
+ }
+ }
+
+ HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT(nCmdID == TCtrl::GetID());
+
+ if (k_(key) == k_SelectedItem)
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ UINT uSel = UI_COLLECTION_INVALIDINDEX;
+ if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) &&
+ ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel))
+ m_uSelected = uSel;
+
+ return SetPropertyVal(key, m_uSelected, ppropvarNewValue);
+ }
+ else
+ {
+ return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ }
+ }
+};
+
+// ItemCollectionImpl: handles item image
+//
+template <class TCtrl, size_t t_items, size_t t_categories = 0>
+class ItemCollectionImpl : public TextCollectionImpl<TCtrl, t_items, t_categories>
+{
+ typedef ItemCollectionImpl<TCtrl, t_items, t_categories> thisClass;
+public:
+ typedef thisClass ItemCollection;
+
+ ItemCollectionImpl()
+ {
+ ZeroMemory(m_aBitmap, sizeof m_aBitmap);
+ }
+
+ CBitmap m_aBitmap[t_items];
+
+ // Operations
+ HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false)
+ {
+ ATLASSERT(uIndex < t_items);
+
+ m_aBitmap[uIndex] = hbm;
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+// Implementation
+ HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uItem < t_items);
+
+ if (k_(key) == k_ItemImage)
+ {
+ if (m_aBitmap[uItem].IsNull())
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem);
+ }
+ return m_aBitmap[uItem].IsNull() ?
+ E_NOTIMPL :
+ SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value);
+ }
+ else
+ {
+ return TextCollection::DoGetItem(uItem, key, value);
+ }
+ }
+};
+
+// ComboCollectionImpl: handles combo text
+//
+template <class TCtrl, size_t t_items, size_t t_categories = 0>
+class ComboCollectionImpl : public ItemCollectionImpl<TCtrl, t_items, t_categories>
+{
+ typedef ComboCollectionImpl<TCtrl, t_items, t_categories> thisClass;
+public:
+ typedef thisClass ComboCollection;
+
+ // Operations
+ HRESULT SetComboText(LPCWSTR sText)
+ {
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ return ribbon.IsRibbonUI() ?
+ ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) :
+ S_OK;
+ }
+
+ LPCWSTR GetComboText()
+ {
+ static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 };
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+ PROPVARIANT var;
+ if (ribbon.IsRibbonUI())
+ {
+ HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var);
+ hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT);
+ return sCombo;
+ }
+ return NULL;
+ }
+};
+
+// CommandCollectionImpl: handles RibbonUI command collection controls
+//
+template <class TCtrl, size_t t_items, size_t t_categories = 0>
+class CommandCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
+{
+ typedef CommandCollectionImpl<TCtrl, t_items, t_categories> thisClass;
+public:
+ typedef thisClass CommandCollection;
+
+ CommandCollectionImpl()
+ {
+ ZeroMemory(m_auCmd, sizeof m_auCmd);
+ ZeroMemory(m_aCmdType, sizeof m_aCmdType);
+ }
+
+ UINT32 m_auCmd[t_items];
+ BYTE m_aCmdType[t_items];
+
+ // Operations
+ HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false)
+ {
+ ATLASSERT(uItem < t_items);
+
+ if (uCommandID == m_auCmd[uItem])
+ return S_OK;
+
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+
+ m_auCmd[uItem] = uCommandID;
+ if (uCommandID != 0)
+ ribbon.UIAddRibbonElement(uCommandID);
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+ HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false)
+ {
+ ATLASSERT(uItem < t_items);
+
+ m_aCmdType[uItem] = (BYTE)type;
+
+ return bUpdate ? InvalidateItems() : S_OK;
+ }
+
+// Implementation
+ HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uItem < t_items);
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+
+ HRESULT hr = E_FAIL;
+ switch (k_(key))
+ {
+ case k_CommandId:
+ if (m_auCmd[uItem] == 0)
+ SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem));
+ hr = SetPropertyVal(key, m_auCmd[uItem], value);
+ break;
+ case k_CommandType:
+ if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN)
+ SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem));
+ hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
+ break;
+ case k_CategoryId:
+ default:
+ hr = Collection::DoGetItem(uItem, key, value);
+ break;
+ }
+
+ return hr;
+ }
+
+ HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false)
+ {
+ ATLASSERT(FALSE);
+ return S_OK;
+ }
+};
+
+// SimpleCollectionImpl: collection class for ribbon simple collection controls
+//
+template <class TCtrl, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
+class SimpleCollectionImpl : public CollectionImplBase<SimpleCollectionImpl<TCtrl, t_size>, t_size>
+{
+ typedef SimpleCollectionImpl<TCtrl, t_size, t_CommandType> thisClass;
+public:
+ typedef CollectionImplBase<thisClass, t_size> CollectionBase;
+ typedef thisClass SimpleCollection;
+
+// Implementation
+ HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uItem < t_size);
+ TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
+
+ HRESULT hr = E_NOTIMPL;
+ switch (k_(key))
+ {
+ case k_ItemImage:
+ if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem))
+ hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value);
+ break;
+ case k_Label:
+ if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem))
+ hr = SetPropertyVal(key, (LPCWSTR)sText, value);
+ break;
+ case k_CommandType:
+ hr = SetPropertyVal(key, t_CommandType, value);
+ break;
+ case k_CommandId:
+ hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value);
+ break;
+ case k_CategoryId:
+ hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ return hr;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Ribbon collection control classes
+
+// CollectionCtrlImpl: specializable class for ribbon collection controls
+//
+template <class T, UINT t_ID, class TCollection>
+class CollectionCtrlImpl : public CommandCtrlImpl<T, t_ID>, public TCollection
+{
+ typedef CollectionCtrlImpl<T, t_ID, TCollection> thisClass;
+public:
+ typedef CommandCtrlImpl<T, t_ID> CommandCtrl;
+ typedef TCollection Collection;
+
+ // Implementation
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT(nCmdID == GetID());
+ ATLASSERT(ppropvarNewValue);
+
+ HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ if FAILED(hr)
+ hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+
+ return hr;
+ }
+
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* /*pCommandExecutionProperties*/)
+ {
+ ATLASSERT (nCmdID == GetID());
+ nCmdID; // avoid level4 warning
+
+ if (key == NULL) // gallery button pressed
+ {
+ GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
+ return S_OK;
+ }
+
+ ATLASSERT(k_(*key) == k_SelectedItem);
+ ATLASSERT(ppropvarValue);
+
+ HRESULT hr = S_OK;
+ UINT32 uSel = 0xffff;
+ hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
+
+ if (SUCCEEDED(hr))
+ {
+ if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel))
+ TCollection::Select(uSel);
+ }
+
+ return hr;
+ }
+};
+
+// ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls
+//
+template <class T, UINT t_ID, UINT t_idTB, size_t t_size>
+class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>, t_size>>
+{
+public:
+ ToolbarGalleryCtrlImpl()
+ {
+ CResource tbres;
+ ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB));
+ _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock();
+ ATLASSERT(pData);
+ ATLASSERT(pData->wVersion == 1);
+
+ WORD* pItems = pData->items();
+ INT j = 0;
+ for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++)
+ {
+ if (pItems[i] != 0)
+ {
+ m_aCmdType[j] = UI_COMMANDTYPE_ACTION;
+ m_auCmd[j++] = pItems[i];
+ }
+ }
+
+ if (j < t_size)
+ Resize(j);
+ }
+
+ HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT(uItem < m_size);
+ ATLASSERT(m_auCmd[uItem]);
+
+ HRESULT hr = E_FAIL;
+ switch (k_(key))
+ {
+ case k_CommandId:
+ hr = SetPropertyVal(key, m_auCmd[uItem], value);
+ break;
+ case k_CommandType:
+ hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
+ break;
+ case k_CategoryId:
+ hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ return hr;
+ }
+};
+
+
+// SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls
+//
+template <class T, UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
+class SimpleCollectionCtrlImpl :
+ public CommandCtrlImpl<T, t_ID>,
+ public SimpleCollectionImpl<SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>, t_size, t_CommandType>
+{
+ typedef SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType> thisClass;
+public:
+ typedef thisClass SimpleCollection;
+
+ SimpleCollectionCtrlImpl() : m_uSelected(0)
+ { }
+
+ UINT m_uSelected;
+
+ HRESULT Select(UINT uItem, bool bUpdate = false)
+ {
+ ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX));
+
+ m_uSelected = uItem;
+
+ return bUpdate ?
+ GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) :
+ S_OK;
+ }
+
+ // Implementation
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT(nCmdID == GetID());
+ ATLASSERT(ppropvarNewValue != NULL);
+
+ HRESULT hr = S_OK;
+ switch (k_(key))
+ {
+ case k_ItemsSource:
+ {
+ ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
+ ATLASSERT(pIUICollection.p);
+ hr = pIUICollection->Clear();
+ for (UINT i = 0; i < t_size; i++)
+ {
+ if FAILED(hr = pIUICollection->Add(m_apItems[i]))
+ break;
+ }
+ ATLASSERT(SUCCEEDED(hr));
+ }
+ break;
+ case k_SelectedItem:
+ hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue);
+ break;
+ default:
+ hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ break;
+ }
+
+ return hr;
+ }
+
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* /*pCommandExecutionProperties*/)
+ {
+ ATLASSERT (nCmdID == GetID());
+ nCmdID; // avoid level 4 warning
+
+ HRESULT hr = S_OK;
+ if (key == NULL) // gallery button pressed
+ {
+ GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
+ return hr;
+ }
+ ATLASSERT(k_(*key) == k_SelectedItem);
+ ATLASSERT(ppropvarValue);
+
+ if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected))
+ GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected);
+
+ return hr;
+ }
+};
+
+// RecentItemsCtrlImpl
+//
+template <class T, UINT t_ID, class TDocList = CRecentDocumentList>
+class RecentItemsCtrlImpl :
+ public CtrlImpl<T, t_ID>,
+ public CollectionImplBase<RecentItemsCtrlImpl<T, t_ID, TDocList>, TDocList::m_nMaxEntries_Max>,
+ public TDocList
+{
+ typedef RecentItemsCtrlImpl<T, t_ID, TDocList> thisClass;
+public:
+ typedef thisClass RecentItems;
+
+ // Implementation
+ HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
+ {
+ ATLASSERT((INT)uItem < GetMaxEntries());
+
+ LPCWSTR sPath = m_arrDocs[uItem].szDocName;
+ HRESULT hr = E_NOTIMPL;
+ switch (k_(key))
+ {
+ case k_Label:
+ hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value);
+ break;
+ case k_LabelDescription:
+ hr = SetPropertyVal(key, sPath, value);
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ return hr;
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT(nCmdID == GetID());
+ ATLASSERT(ppropvarNewValue);
+
+ HRESULT hr = S_OK;
+ switch (k_(key))
+ {
+ case k_RecentItems:
+ if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize()))
+ {
+ const int iLastIndex = m_arrDocs.GetSize() - 1;
+ for (LONG i = 0; i <= iLastIndex; i++)
+ SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order
+
+ hr = SetPropertyVal(key, psa, ppropvarNewValue);
+ SafeArrayDestroy(psa);
+ }
+ break;
+ default:
+ hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ break;
+ }
+
+ return hr;
+ }
+
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* /*pCommandExecutionProperties*/)
+ {
+ ATLASSERT(nCmdID == GetID());
+ nCmdID; // avoid level 4 warning
+ ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);
+ verb; // avoid level 4 warning
+ ATLASSERT((key) && (k_(*key) == k_SelectedItem));
+ ATLASSERT(ppropvarValue);
+
+ UINT32 uSel = 0xffff;
+ HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
+ if SUCCEEDED(hr)
+ {
+ ATLASSERT(uSel < (UINT)GetMaxEntries());
+ GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel);
+ }
+
+ return hr;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Ribbon stand-alone control classes
+
+// FontCtrlImpl
+//
+template <class T, UINT t_ID>
+class FontCtrlImpl : public CtrlImpl<T, t_ID>
+{
+public:
+
+ CharFormat m_cf;
+
+// Implementation
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* pCommandExecutionProperties)
+ {
+ ATLASSERT (nCmdID == GetID());
+ nCmdID; // avoid level 4 warning
+ ATLASSERT ((key) && (k_(*key) == k_FontProperties));
+ key; // avoid level 4 warning
+
+ HRESULT hr = E_INVALIDARG;
+ switch (verb)
+ {
+ case UI_EXECUTIONVERB_PREVIEW:
+ case UI_EXECUTIONVERB_EXECUTE:
+ ATLASSERT(pCommandExecutionProperties);
+ PROPVARIANT propvar;
+
+ if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar)))
+ m_cf << ATL::CComQIPtr<IPropertyStore>(propvar.punkVal);
+ break;
+
+ case UI_EXECUTIONVERB_CANCELPREVIEW:
+ ATLASSERT(ppropvarValue);
+ ATL::CComPtr<IPropertyStore> pStore;
+
+ if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore)))
+ m_cf << pStore;
+ break;
+ }
+
+ if (SUCCEEDED(hr))
+ GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf);
+ else
+ ATLASSERT(FALSE);
+
+ return hr;
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf)))
+ {
+ ATL::CComQIPtr<IPropertyStore> pStore(ppropvarCurrentValue->punkVal);
+ m_cf >> pStore;
+ return SetPropertyVal(key, pStore.p, ppropvarNewValue);
+ }
+ else
+ {
+ return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ }
+ }
+};
+
+// ColorCtrlImpl
+//
+template <class T, UINT t_ID>
+class ColorCtrlImpl : public CommandCtrlImpl<T, t_ID>
+{
+public:
+ ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/
+ { }
+
+ COLORREF m_color;
+ UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE
+ Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel
+ ATL::CSimpleArray<COLORREF> m_aColors[2];
+ ATL::CSimpleArray<LPCWSTR> m_aTooltips[2];
+
+ // Operations
+ HRESULT SetColor(COLORREF color, bool bUpdate = false)
+ {
+ if (m_colorType != UI_SWATCHCOLORTYPE_RGB)
+ SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate);
+ m_color = color;
+ return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK;
+ }
+
+ HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false)
+ {
+ m_colorType = type;
+ return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK;
+ }
+
+ HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel));
+ m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel;
+ return bUpdate ? SetProperty(key, sLabel) : S_OK;
+ }
+
+ HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors));
+
+ const INT ic = k_(key) - k_ThemeColors;
+ m_aColors[ic].RemoveAll();
+ while (*pColor != 0x800080) /*MAGENTA*/
+ m_aColors[ic].Add(*pColor++);
+
+ if (bUpdate)
+ {
+ PROPVARIANT var;
+ if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var))
+ return SetProperty(key, var);
+ else
+ return E_INVALIDARG;
+ }
+ else
+ {
+ return S_OK;
+ }
+ }
+
+ HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips));
+
+ const INT ic = k_(key) - k_ThemeColorsTooltips;
+ m_aTooltips[ic].RemoveAll();
+ while (*ppsTT)
+ m_aTooltips[ic].Add(*ppsTT++);
+
+ if (bUpdate)
+ {
+ PROPVARIANT var;
+ if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var))
+ return SetProperty(key, var);
+ else
+ return E_INVALIDARG;
+ }
+ else
+ {
+ return S_OK;
+ }
+ }
+
+ // Implementation
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* pCommandExecutionProperties)
+ {
+ ATLASSERT (nCmdID == GetID());
+ nCmdID; // avoid level 4 warning
+ ATLASSERT (key && (k_(*key) == k_ColorType));
+ key; // avoid level 4 warning
+ ATLASSERT (ppropvarValue);
+
+ HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType);
+ ATLASSERT(SUCCEEDED(hr));
+
+ if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB))
+ {
+ ATLASSERT(pCommandExecutionProperties);
+ PROPVARIANT var;
+ if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var))
+ hr = PropVariantToUInt32(var, &m_color);
+ }
+
+ if SUCCEEDED(hr)
+ GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color);
+ else
+ ATLASSERT(FALSE); // something was wrong
+
+ return hr;
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT (nCmdID == GetID());
+
+ HRESULT hr = E_NOTIMPL;
+
+ switch (k_(key))
+ {
+ case k_ColorType:
+ hr = SetPropertyVal(key, m_colorType, ppropvarNewValue);
+ break;
+ case k_Color:
+ if (m_color == 0x800080) /*MAGENTA*/
+ m_color = GetWndRibbon().OnRibbonQueryColor(GetID());
+ hr = SetPropertyVal(key, m_color, ppropvarNewValue);
+ break;
+ case k_ColorMode:
+ break;
+ case k_ThemeColorsCategoryLabel:
+ case k_StandardColorsCategoryLabel:
+ case k_RecentColorsCategoryLabel:
+ case k_AutomaticColorLabel:
+ case k_NoColorLabel:
+ case k_MoreColorsLabel:
+ {
+ const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel;
+ if (m_sLabels[iLabel].IsEmpty())
+ if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key))
+ m_sLabels[iLabel] = psLabel;
+ if (!m_sLabels[iLabel].IsEmpty())
+ hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue);
+ }
+ break;
+ case k_ThemeColors:
+ case k_StandardColors:
+ {
+ const INT ic = k_(key) - k_ThemeColors;
+ if (!m_aColors[ic].GetSize())
+ if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key))
+ SetColorArray(key, pColor);
+ if (INT iMax = m_aColors[ic].GetSize())
+ hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue);
+ }
+ break;
+ case k_ThemeColorsTooltips:
+ case k_StandardColorsTooltips:
+ {
+ const INT ic = k_(key) - k_ThemeColorsTooltips;
+ if (m_aTooltips[ic].GetSize() == 0)
+ if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key))
+ SetColorTooltips(key, ppsTT);
+ if (INT iMax = m_aTooltips[ic].GetSize())
+ hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue);
+ }
+ break;
+ default:
+ hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ break;
+ }
+
+ return hr;
+ }
+};
+
+// SpinnerCtrlImpl
+//
+template <class T, UINT t_ID, typename V = LONG>
+class SpinnerCtrlImpl : public CtrlImpl<T, t_ID>
+{
+public:
+ SpinnerCtrlImpl()
+ {
+ m_Values[0] = m_Values[2] = m_Values[4] = 0;
+ m_Values[1] = 100;
+ m_Values[3] = 1;
+ }
+
+ V m_Values[5];
+ // k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces
+
+ Text m_FormatString;
+ Text m_RepresentativeString;
+
+ // Operations
+ HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false)
+ {
+ return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate);
+ }
+
+ HRESULT SetMin(V vMin, bool bUpdate = false)
+ {
+ return SetValue(UI_PKEY_MinValue, vMin, bUpdate);
+ }
+
+ HRESULT SetMax(V vMax, bool bUpdate = false)
+ {
+ return SetValue(UI_PKEY_MaxValue, vMax, bUpdate);
+ }
+
+ HRESULT SetVal(V vVal, bool bUpdate = false)
+ {
+ return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate);
+ }
+
+ HRESULT SetIncrement(V vIncrement, bool bUpdate = false)
+ {
+ return SetValue(UI_PKEY_Increment, vIncrement, bUpdate);
+ }
+
+ HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false)
+ {
+ return SetText(UI_PKEY_FormatString, sFormat, bUpdate);
+ }
+
+ HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false)
+ {
+ return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate);
+ }
+
+ // Implementation
+ HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false)
+ {
+ switch (k_(key))
+ {
+ case k_FormatString:
+ m_FormatString = sText;
+ break;
+ case k_RepresentativeString:
+ m_RepresentativeString = sText;
+ break;
+ default:
+ return CtrlImpl::SetText(key, sText, bUpdate);
+ }
+
+ return bUpdate ?
+ GetWndRibbon().InvalidateProperty(GetID(), key) :
+ S_OK;
+ }
+
+ HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false)
+ {
+ ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));
+
+ const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;
+ m_Values[iVal] = val;
+
+ if (bUpdate)
+ {
+ if(k_(key) == k_DecimalValue)
+ {
+ DECIMAL decVal;
+ InitDecimal(val, &decVal);
+ return SetProperty(key, &decVal);
+ }
+ else
+ {
+ return GetWndRibbon().InvalidateProperty(GetID(), key);
+ }
+ }
+ else
+ {
+ return S_OK;
+ }
+ }
+
+ HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal)
+ {
+ return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal);
+ }
+
+ HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal)
+ {
+ return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal);
+ }
+
+ HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv)
+ {
+ ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));
+
+ const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;
+
+ QueryValue(key, m_Values + iVal);
+
+ if (k_(key) == k_DecimalPlaces)
+ {
+ return SetPropertyVal(key, m_Values[iVal], ppv);
+ }
+ else
+ {
+ DECIMAL decVal;
+ InitDecimal(m_Values[iVal], &decVal);
+ return SetPropertyVal(key, &decVal, ppv);
+ }
+ }
+
+ HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv)
+ {
+ if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key))
+ sVal = sNew;
+ return SetPropertyVal(key, (LPCWSTR)sVal, ppv);
+ }
+
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* /*pCommandExecutionProperties*/)
+ {
+ ATLASSERT (nCmdID == GetID());
+ nCmdID; // avoid level 4 warning
+ ATLASSERT (key && (k_(*key) == k_DecimalValue));
+ key; // avoid level 4 warning
+ ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE);
+ verb; // avoid level 4 warning
+
+ DECIMAL decVal;
+
+ HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal);
+ hr = InitVal(m_Values[0], &decVal);
+
+ GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]);
+
+ return hr;
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ ATLASSERT (nCmdID == GetID());
+
+ HRESULT hr = E_NOTIMPL;
+ switch (k_(key))
+ {
+ case k_DecimalPlaces:
+ case k_DecimalValue:
+ case k_Increment:
+ case k_MaxValue:
+ case k_MinValue:
+ hr = OnGetValue(key, ppropvarNewValue);
+ break;
+ case k_FormatString:
+ if (m_FormatString.IsEmpty())
+ return OnGetText(key, m_FormatString, ppropvarNewValue);
+ break;
+ case k_RepresentativeString:
+ if (m_RepresentativeString.IsEmpty())
+ return OnGetText(key, m_RepresentativeString, ppropvarNewValue);
+ break;
+ default:
+ hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ break;
+ }
+
+ return hr;
+ }
+
+ // decimal conversion helpers
+ static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal)
+ {
+ return ::VarDecFromI4(val, pDecimal);
+ }
+
+ static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal)
+ {
+ return ::VarDecFromR8(val, pDecimal);
+ }
+
+ static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal)
+ {
+ return ::VarI4FromDec(pDecimal, &val);
+ }
+
+ static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal)
+ {
+ return ::VarR8FromDec(pDecimal, &val);
+ }
+};
+
+// CRibbonImpl Ribbon implementation class
+//
+template <class T>
+class CRibbonImpl :
+ public CRibbonUpdateUI<T>,
+ public ICtrl,
+ public IUIApplication,
+ public IUICommandHandler
+{
+ typedef CRibbonImpl<T> thisClass;
+public:
+ typedef thisClass Ribbon;
+ typedef T WndRibbon;
+
+ CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL)
+ {
+#ifdef _DEBUG
+ m_cRef = 1;
+#endif
+ pWndRibbon = static_cast<T*>(this);
+ HRESULT hr = ::CoInitialize(NULL);
+ if(SUCCEEDED(hr))
+ if (RunTimeHelper::IsRibbonUIAvailable())
+ hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework);
+ else
+ ATLTRACE(L"Ribbon UI not available\n");
+
+ if FAILED(hr)
+ ATLTRACE(L"Ribbon construction failed\n");
+
+ ATLASSERT(SUCCEEDED(hr));
+ }
+
+ ~CRibbonImpl()
+ {
+ ::GlobalFree(m_hgRibbonSettings);
+ m_pIUIFramework.Release();
+ ::CoUninitialize();
+ }
+
+ ICtrl& GetRibbonCtrl(UINT)
+ {
+ return static_cast<ICtrl&>(*this);
+ }
+
+ ATL::CComPtr<IUIFramework> m_pIUIFramework;
+ HGLOBAL m_hgRibbonSettings;
+ bool m_bRibbonUI;
+
+ bool IsRibbonUI()
+ {
+ return m_bRibbonUI;
+ }
+
+ IUIFramework* GetIUIFrameworkPtr()
+ {
+ return m_pIUIFramework;
+ }
+
+ template <typename I>
+ I* GetRibbonViewPtr(UINT32 uID)
+ {
+ ATLASSERT(m_pIUIFramework);
+ ATL::CComPtr<I> pI;
+ return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ?
+ pI :
+ NULL;
+ }
+
+ IUIRibbon* GetRibbonPtr()
+ {
+ return GetRibbonViewPtr<IUIRibbon>(0);
+ }
+
+ IUIContextualUI* GetMenuPtr(UINT32 uID)
+ {
+ ATLASSERT(uID);
+ return GetRibbonViewPtr<IUIContextualUI>(uID);
+ }
+
+ UINT GetRibbonHeight()
+ {
+ ATLASSERT(IsRibbonUI());
+
+ UINT32 cy = 0;
+ if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
+ pIUIRibbon->GetHeight(&cy);
+ return cy;
+ }
+
+ HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON")
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI());
+ ATLASSERT(pT->IsWindow());
+
+ HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this);
+
+ if (hr == S_OK)
+ hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName);
+
+ return hr;
+ }
+
+ HRESULT DestroyRibbon()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI());
+ ATLASSERT(pT->IsWindow());
+
+ HRESULT hRes = m_pIUIFramework->Destroy();
+ if (!RunTimeHelper::IsWin7())
+ pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround
+ return hRes;
+ }
+
+// Ribbon persistency
+ HRESULT operator >>(IStream* pIStream)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(pIStream);
+
+ HRESULT hr = E_FAIL;
+ if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
+ {
+ const LARGE_INTEGER li0 = { 0 };
+ pIStream->Seek(li0, STREAM_SEEK_SET, NULL);
+ hr = pIUIRibbon->SaveSettingsToStream(pIStream);
+ pIStream->Commit(STGC_DEFAULT);
+ }
+
+ return hr;
+ }
+
+ HRESULT operator <<(IStream* pIStream)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(pIStream);
+
+ HRESULT hr = E_FAIL;
+ if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
+ {
+ const LARGE_INTEGER li0 = { 0 };
+ pIStream->Seek(li0, STREAM_SEEK_SET, NULL);
+ hr = pIUIRibbon->LoadSettingsFromStream(pIStream);
+ }
+
+ return hr;
+ }
+
+ void ResetRibbonSettings()
+ {
+ if (m_hgRibbonSettings != NULL)
+ {
+ ::GlobalFree(m_hgRibbonSettings);
+ m_hgRibbonSettings = NULL;
+ }
+ }
+
+ HRESULT SaveRibbonSettings()
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(static_cast<T*>(this)->IsWindow());
+
+ HRESULT hr = E_FAIL;
+ ATL::CComPtr<IStream> pIStream;
+
+ if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))
+ hr = *this >> pIStream;
+
+ if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL))
+ hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings);
+
+ if FAILED(hr)
+ ResetRibbonSettings();
+
+ return hr;
+ }
+
+ HRESULT RestoreRibbonSettings()
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(m_hgRibbonSettings);
+ ATLASSERT(static_cast<T*>(this)->IsWindow());
+
+ HRESULT hr = E_FAIL;
+ ATL::CComPtr<IStream> pIStream;
+
+ if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))
+ hr = *this << pIStream;
+
+ if FAILED(hr)
+ ResetRibbonSettings();
+
+ return hr;
+ }
+
+// QAT dock states
+ UI_CONTROLDOCK GetQATDock()
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+
+ UINT32 uDock = 0;
+ PROPVARIANT propvar;
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
+
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) &&
+ SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock)))
+ return (UI_CONTROLDOCK)uDock;
+
+ ATLASSERT(FALSE); // something was wrong
+ return (UI_CONTROLDOCK)0;
+ }
+
+ bool SetQATDock(UI_CONTROLDOCK dockState)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+
+ PROPVARIANT propvar;
+ ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar)));
+
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar)))
+ {
+ pIPS->Commit();
+ return true;
+ }
+
+ ATLASSERT(FALSE); // something was wrong
+ return false;
+ }
+
+// Ribbon display states
+ bool GetRibbonDisplayState(REFPROPERTYKEY key)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+ ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));
+
+ PROPVARIANT propvar;
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
+
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))
+ {
+ BOOL bState = FALSE;
+ if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState))
+ return (bState != FALSE);
+ }
+
+ ATLASSERT(FALSE); // something was wrong
+ return false;
+ }
+
+ bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+ ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));
+
+ PROPVARIANT propvar;
+ ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar)));
+
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
+
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))
+ {
+ pIPS->Commit();
+ return true;
+ }
+
+ ATLASSERT(FALSE); // something was wrong
+ return false;
+ }
+
+ bool IsRibbonMinimized()
+ {
+ return GetRibbonDisplayState(UI_PKEY_Minimized);
+ }
+
+ bool MinimizeRibbon(bool bMinimize = true)
+ {
+ return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize);
+ }
+
+ bool IsRibbonHidden()
+ {
+ return !GetRibbonDisplayState(UI_PKEY_Viewable);
+ }
+
+ bool HideRibbon(bool bHide = true)
+ {
+ return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide);
+ }
+
+// Ribbon colors
+ UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+ ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));
+
+ PROPVARIANT propvar;
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());
+
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))
+ {
+ UINT32 color = 0;
+ if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color))
+ return color;
+ }
+
+ ATLASSERT(FALSE); // something was wrong
+ return 0;
+ }
+
+ bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+ ATLASSERT(IsRibbonUI());
+ ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));
+
+ PROPVARIANT propvar;
+ ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar)));
+
+ ATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());
+
+ if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))
+ {
+ pIPS->Commit();
+ return true;
+ }
+
+ ATLASSERT(FALSE); // something was wrong
+ return false;
+ }
+
+// Ribbon modes
+ HRESULT SetRibbonModes(INT32 iModes)
+ {
+ ATLASSERT(IsRibbonUI());
+ return GetIUIFrameworkPtr()->SetModes(iModes);
+ }
+
+// Ribbon contextual tab
+ UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID)
+ {
+ ATLASSERT(GetIUIFrameworkPtr());
+
+ PROPVARIANT propvar;
+ if (IsRibbonUI() &&
+ SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar)))
+ {
+ UINT uav;
+ if (SUCCEEDED(PropVariantToUInt32(propvar, &uav)))
+ {
+ CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);
+ CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE);
+ return (UI_CONTEXTAVAILABILITY)uav;
+ }
+ }
+
+ return UI_CONTEXTAVAILABILITY_NOTAVAILABLE;
+ }
+
+ HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav)
+ {
+ CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);
+ CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE);
+
+ return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav));
+ }
+
+// Ribbon context menu
+ bool HasRibbonMenu(UINT32 uID)
+ {
+ ATL::CComPtr<IUIContextualUI> pI = GetMenuPtr(uID);
+ return pI != NULL;
+ }
+
+ HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y)
+ {
+ ATLASSERT(HasRibbonMenu(uID));
+
+ return IsRibbonUI() ?
+ ATL::CComPtr<IUIContextualUI>(GetMenuPtr(uID))->ShowAtLocation(x, y) :
+ E_FAIL;
+ }
+
+ HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam)
+ {
+ return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ }
+
+// Overrideables
+ HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/)
+ {
+ return DefRibbonQueryImage(nCmdID);
+ }
+
+ LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)
+ {
+ return DefRibbonQueryText(nCmdID, key);
+ }
+
+ bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)
+ {
+ return DefRibbonQueryState(nCmdID, key);
+ }
+
+ UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID)
+ {
+ DWORD dwState = UIGetState(nCmdID);
+ return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ?
+ UI_CONTEXTAVAILABILITY_NOTAVAILABLE :
+ (((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ?
+ UI_CONTEXTAVAILABILITY_ACTIVE :
+ UI_CONTEXTAVAILABILITY_AVAILABLE);
+ }
+
+ LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/)
+ {
+ return NULL;
+ }
+
+ LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/)
+ {
+ return L"Category";
+ }
+
+ UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)
+ {
+ return 0;
+ }
+
+ LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return DefRibbonQueryItemText(uCtrlID, uItem);
+ }
+
+ bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/)
+ {
+ return false;
+ }
+
+ HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return DefRibbonQueryItemImage(uCtrlID, uItem);
+ }
+
+ UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return DefRibbonQueryItemCommand(uCtrlID, uItem);
+ }
+
+ UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)
+ {
+ return UI_COMMANDTYPE_ACTION;
+ }
+
+ LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath)
+ {
+ return ::PathFindFileName(sPath);
+ }
+
+ bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/)
+ {
+ return false;
+ }
+
+ bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/)
+ {
+ return false;
+ }
+
+ bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/)
+ {
+ return false;
+ }
+
+ COLORREF OnRibbonQueryColor(UINT /*nCmdID*/)
+ {
+ return 0x800080; /*MAGENTA*/
+ }
+
+ LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
+ {
+ return NULL;
+ }
+
+ COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
+ {
+ return NULL;
+ }
+
+ LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
+ {
+ return NULL;
+ }
+
+ bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem)
+ {
+ DefCommandExecute(MAKELONG(uCtrlID, verb), uItem);
+ return true;
+ }
+
+ void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)
+ {
+ DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color);
+ }
+
+ void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf)
+ {
+ DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf);
+ }
+
+ void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal)
+ {
+ DefCommandExecute(uCtrlID, *pVal);
+ }
+
+ void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal)
+ {
+ DefCommandExecute(uCtrlID, (LPARAM)pVal);
+ }
+
+ void OnRibbonCommandExecute(UINT32 uCmdID)
+ {
+ DefCommandExecute(uCmdID);
+ }
+
+// Default implementations
+ HBITMAP DefRibbonQueryImage(UINT nCmdID)
+ {
+ return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION);
+ }
+
+ bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)
+ {
+ DWORD dwState = UIGetState(nCmdID);
+ bool bRet = false;
+ switch (k_(key))
+ {
+ case k_BooleanValue:
+ bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED;
+ break;
+ case k_Enabled:
+ bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED;
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ return bRet;
+ }
+
+ LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)
+ {
+ static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
+
+ if (k_(key) == k_Label)
+ return UIGetText(nCmdID);
+
+ if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT))
+ {
+ PWCHAR pTitle = wcschr(sText, L'\n');
+ switch (k_(key))
+ {
+ case k_Keytip:
+ if (PWCHAR pAmp = wcschr(sText, L'&'))
+ pTitle = pAmp;
+ if (pTitle != NULL)
+ *(pTitle + 2) = NULL; // fall through
+ case k_TooltipTitle:
+ return pTitle ? ++pTitle : NULL;
+ case k_TooltipDescription:
+ case k_LabelDescription:
+ if (pTitle != NULL)
+ *pTitle = NULL;
+ return sText;
+ }
+ }
+
+ return NULL;
+ }
+
+ LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription);
+ }
+
+ HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return DefRibbonQueryImage(uCtrlID + 1 + uItem);
+ }
+
+ UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)
+ {
+ return uCtrlID + 1 + uItem;
+ }
+
+ void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)
+ {
+ switch(uType)
+ {
+ case UI_SWATCHCOLORTYPE_RGB:
+ break;
+ case UI_SWATCHCOLORTYPE_AUTOMATIC:
+ color = ::GetSysColor(COLOR_WINDOWTEXT);
+ break;
+ case UI_SWATCHCOLORTYPE_NOCOLOR:
+ color = ::GetSysColor(COLOR_WINDOW);
+ break;
+ default:
+ ATLASSERT(FALSE);
+ break;
+ }
+
+ DefCommandExecute(MAKELONG(uCtrlID, verb), color);
+ }
+
+ void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0)
+ {
+ static_cast<T*>(this)->PostMessage(WM_COMMAND, uCmd, lParam);
+ }
+
+// Elements setting helpers
+ HRESULT InvalidateCtrl(UINT32 nID)
+ {
+ return IsRibbonUI() ?
+ GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) :
+ E_FAIL;
+ }
+
+ HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)
+ {
+ return IsRibbonUI() ?
+ GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) :
+ E_FAIL;
+ }
+
+ template <typename V>
+ HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val)
+ {
+ if (IsRibbonUI())
+ {
+ PROPVARIANT var;
+ if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var)))
+ {
+ return SetProperty(wID, key, var);
+ }
+ return E_INVALIDARG;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+ }
+
+ template <>
+ HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var)
+ {
+ return IsRibbonUI() ?
+ GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) :
+ E_FAIL;
+ }
+
+// Interfaces
+ // IUIApplication
+ STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32)
+ {
+ switch (verb)
+ {
+ case UI_VIEWVERB_CREATE:
+ m_bRibbonUI = true;
+ if (m_hgRibbonSettings != NULL)
+ RestoreRibbonSettings();
+ break;
+ case UI_VIEWVERB_SIZE:
+ static_cast<T*>(this)->UpdateLayout(FALSE);
+ break;
+ case UI_VIEWVERB_DESTROY:
+ SaveRibbonSettings();
+ m_bRibbonUI = false;
+ break;
+ }
+
+ return S_OK;
+ }
+
+ STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler)
+ {
+ UIAddRibbonElement(nCmdID);
+ if (typeID == UI_COMMANDTYPE_CONTEXT)
+ CUpdateUIBase::UIEnable(nCmdID, false);
+ *ppCommandHandler = this;
+ return S_OK;
+ }
+
+ STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*)
+ {
+ UIRemoveRibbonElement(nCmdID);
+ return S_OK;
+ }
+
+ // IUICommandHandler
+ STDMETHODIMP Execute(UINT nCmdID,
+ UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key,
+ const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* pCommandExecutionProperties)
+ {
+ T* pT =static_cast<T*>(this);
+ return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);
+ }
+
+ STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
+ {
+ T* pT =static_cast<T*>(this);
+ return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
+ }
+
+#ifdef _DEBUG
+ // IUnknown methods (heavyweight)
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0) // NoOp for breakpoint
+ {
+ cRef = 0;
+ }
+
+ return cRef;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
+ {
+ if (ppv == NULL)
+ {
+ return E_POINTER;
+ }
+ else if ((iid == __uuidof(IUnknown)) ||
+ (iid == __uuidof(IUICommandHandler)) ||
+ (iid == __uuidof(IUIApplication)))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ return E_NOINTERFACE;
+ }
+ }
+
+ LONG m_cRef;
+#else
+ // IUnknown methods (lightweight)
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
+ {
+ if ((iid == __uuidof(IUnknown)) ||
+ (iid == __uuidof(IUICommandHandler)) ||
+ (iid == __uuidof(IUIApplication)))
+ {
+ *ppv = this;
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+ }
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return 1;
+ }
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ return 1;
+ }
+#endif
+
+// CRibbonImpl ICtrl implementation
+ virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
+ const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
+ IUISimplePropertySet* /*pCommandExecutionProperties*/)
+ {
+ if (key != NULL)
+ {
+ if(k_(*key) != k_BooleanValue)
+ {
+ ATLTRACE(L"Control ID %d is not handled\n", nCmdID);
+ return E_NOTIMPL;
+ }
+ BOOL bChecked = FALSE;
+ ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked)));
+ CUpdateUIBase::UISetCheck(nCmdID, bChecked);
+ }
+
+ ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);
+ verb; // avoid level 4 warning
+
+ static_cast<T*>(this)->OnRibbonCommandExecute(nCmdID);
+
+ return S_OK;
+ }
+
+ virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
+ const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue)
+ {
+ T* pT = static_cast<T*>(this);
+ HRESULT hr = E_NOTIMPL;
+ switch (k_(key))
+ {
+ case k_LargeImage:
+ case k_LargeHighContrastImage:
+ case k_SmallImage:
+ case k_SmallHighContrastImage:
+ if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key))
+ hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue);
+ break;
+ case k_Label:
+ case k_Keytip:
+ case k_TooltipTitle:
+ case k_TooltipDescription:
+ case k_LabelDescription:
+ if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key))
+ hr = SetPropertyVal(key, sText, ppropvarNewValue);
+ break;
+ case k_BooleanValue:
+ case k_Enabled:
+ hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue);
+ break;
+ case k_ContextAvailable:
+ hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue);
+ break;
+ }
+
+ return hr;
+ }
+
+// CRibbonImpl::CRibbonXXXCtrl specialized classes
+ //CRibbonComboCtrl
+ template <UINT t_ID, size_t t_items, size_t t_categories = 0>
+ class CRibbonComboCtrl : public CollectionCtrlImpl<T, t_ID, ComboCollectionImpl<CRibbonComboCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
+ {
+ public:
+ CRibbonComboCtrl()
+ { }
+ };
+
+ // CRibbonItemGalleryCtrl
+ template <UINT t_ID, size_t t_items, size_t t_categories = 0>
+ class CRibbonItemGalleryCtrl : public CollectionCtrlImpl<T, t_ID, ItemCollectionImpl<CRibbonItemGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
+ {
+ public:
+ CRibbonItemGalleryCtrl()
+ { }
+ };
+
+ // CRibbonCommandGalleryCtrl
+ template <UINT t_ID, size_t t_items, size_t t_categories = 0>
+ class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<CRibbonCommandGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
+ {
+ public:
+ CRibbonCommandGalleryCtrl()
+ { }
+ };
+
+ // CRibbonToolbarGalleryCtrl
+ template <UINT t_ID, UINT t_idTB, size_t t_size>
+ class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>
+ { };
+
+ // CRibbonSimpleComboCtrl
+ template <UINT t_ID, size_t t_size>
+ class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size>
+ { };
+
+ // CRibbonSimpleGalleryCtrl
+ template <UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
+ class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>
+ { };
+
+ //CRibbonRecentItemsCtrl
+ template <UINT t_ID, class TDocList = CRecentDocumentList>
+ class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl<T, t_ID, TDocList>
+ {
+ public:
+ CRibbonRecentItemsCtrl()
+ { }
+ };
+
+ // CRibbonColorCtrl
+ template <UINT t_ID>
+ class CRibbonColorCtrl : public ColorCtrlImpl<T, t_ID>
+ {
+ public:
+ CRibbonColorCtrl()
+ { }
+ };
+
+ //CRibbonFontCtrl
+ template <UINT t_ID>
+ class CRibbonFontCtrl : public FontCtrlImpl<T, t_ID>
+ {
+ public:
+ CRibbonFontCtrl()
+ { }
+ };
+
+ // CRibbonSpinnerCtrl
+ template <UINT t_ID>
+ class CRibbonSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, LONG>
+ {
+ public:
+ CRibbonSpinnerCtrl()
+ { }
+ };
+
+ // CRibbonFloatSpinnerCtrl
+ template <UINT t_ID>
+ class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, DOUBLE>
+ {
+ public:
+ CRibbonFloatSpinnerCtrl()
+ {
+ m_Values[4] = 1; // 1 decimal
+ }
+ };
+
+ // CRibbonCommandCtrl
+ template <UINT t_ID>
+ class CRibbonCommandCtrl : public CommandCtrlImpl<T, t_ID>
+ {
+ public:
+ CRibbonCommandCtrl()
+ { }
+ };
+
+// Control classes access to T instance (re-initialized in constructor)
+ static T* pWndRibbon;
+};
+
+template <class T>
+__declspec(selectany) T* CRibbonImpl<T>::pWndRibbon;
+
+// Control map element
+#pragma warning (disable : 4510 610) // missing default constructor
+typedef struct
+{
+ UINT uID;
+ ICtrl& ctrl;
+} _ribbonCtrl;
+#pragma warning (default : 4510 610) // missing default constructor
+
+}; // namespace RibbonUI
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RibbonUI Control map
+
+// Control map macros
+#define BEGIN_RIBBON_CONTROL_MAP(theClass) \
+ RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \
+ { \
+ RibbonUI::_ribbonCtrl _ctrls[] = \
+ {
+
+#define RIBBON_CONTROL(member) {member.GetID(), static_cast<RibbonUI::ICtrl&>(member)},
+
+#define END_RIBBON_CONTROL_MAP() \
+ {0, *this} \
+ }; \
+ int i = 0; \
+ for(; i < _countof(_ctrls) - 1; i++) \
+ if (_ctrls[i].uID == id) \
+ break; \
+ return _ctrls[i].ctrl; \
+}
+
+// Control message map macros
+#define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \
+ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define RIBBON_COMBO_CONTROL_HANDLER(id, func) \
+ RIBBON_GALLERY_CONTROL_HANDLER(id, func)
+
+#define RIBBON_FONT_CONTROL_HANDLER(id, func) \
+ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define RIBBON_COLOR_CONTROL_HANDLER(id, func) \
+ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \
+ if(uMsg == WM_COMMAND && id == wParam) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((WORD)wParam, (LONG)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \
+ if(uMsg == WM_COMMAND && id == wParam) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+// Handler prototypes
+/*
+ LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);
+ LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);
+ LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled);
+ LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled);
+ LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled);
+ LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled);
+*/
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Ribbon frame classes
+
+// CRibbonFrameWindowImplBase
+//
+template <class T, class TFrameImpl>
+class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl<T>
+{
+ typedef TFrameImpl baseFrame;
+ bool m_bUseCommandBarBitmaps;
+ bool m_bWin7Fix;
+
+public:
+// Construction
+ CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) :
+ m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false)
+ {
+ __if_not_exists(T::m_CmdBar)
+ {
+ m_bUseCommandBarBitmaps = false;
+ }
+ }
+
+// Win7 Aero fix helpers
+ void ResetFrame()
+ {
+ const MARGINS margins = { 0 };
+ ::DwmExtendFrameIntoClientArea(m_hWnd, &margins);
+ }
+
+ INT CalcWin7Fix()
+ {
+ ResetFrame();
+ RECT rc = { 0 };
+ ::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0));
+ return -rc.top;
+ }
+
+ bool NeedWin7Fix()
+ {
+ BOOL bComp = FALSE;
+ return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp;
+ }
+
+// Operations
+ bool UseCommandBarBitmaps(bool bUse)
+ {
+ __if_exists(T::m_CmdBar)
+ {
+ return m_bUseCommandBarBitmaps = bUse;
+ }
+ __if_not_exists(T::m_CmdBar)
+ {
+ bUse; // avoid level 4 warning
+ return false;
+ }
+ }
+
+ bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON")
+ {
+ if (!RunTimeHelper::IsRibbonUIAvailable())
+ return false;
+
+ ATLASSERT(GetIUIFrameworkPtr());
+
+ if (IsRibbonUI() == bShow)
+ return bShow;
+
+ bool bVisible = (IsWindowVisible() != FALSE);
+ if(bVisible && !bShow)
+ SetRedraw(FALSE);
+
+ if (bShow && ::IsWindow(m_hWndToolBar))
+ {
+ ::ShowWindow(m_hWndToolBar, SW_HIDE);
+ UpdateLayout();
+ }
+
+ m_bWin7Fix = !bShow;
+
+ HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon();
+
+ m_bWin7Fix = SUCCEEDED(hr) && !bShow;
+
+ if (SUCCEEDED(hr))
+ {
+ if(::IsWindow(m_hWndToolBar) && !bShow)
+ {
+ ::ShowWindow(m_hWndToolBar, SW_SHOWNA);
+ UpdateLayout();
+ }
+ else if (bShow)
+ {
+ PostMessage(WM_SIZE);
+ SetRibbonModes(imodes);
+ }
+ }
+
+ if(bVisible && !bShow)
+ {
+ SetRedraw(TRUE);
+ RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ }
+
+ return SUCCEEDED(hr) ? bShow : !bShow;
+ }
+
+// Overrideables
+ HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key)
+ {
+ if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps)
+ {
+ if (HBITMAP hbm = GetCommandBarBitmap(nCmdID))
+ return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+ }
+
+ return DefRibbonQueryImage(nCmdID);
+ }
+
+ BEGIN_MSG_MAP(CRibbonFrameWindowImplBase)
+ if (!IsRibbonUI() && NeedWin7Fix())
+ {
+ MESSAGE_HANDLER(WM_SIZING, OnSizing)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
+ MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize)
+ }
+ CHAIN_MSG_MAP(CRibbonUpdateUI<T>)
+ CHAIN_MSG_MAP(baseFrame)
+ END_MSG_MAP()
+
+// Message handlers for Win7 Aero
+ LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ switch (wParam)
+ {
+ case WMSZ_TOP:
+ case WMSZ_TOPLEFT:
+ case WMSZ_TOPRIGHT:
+ SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ break;
+ default:
+ DefWindowProc();
+ break;
+ }
+
+ return 1; // handled
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if (wParam != SIZE_MINIMIZED)
+ SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam != WA_INACTIVE)
+ SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ ATLASSERT(!IsRibbonUI() && NeedWin7Fix());
+
+ LRESULT lRet = DefWindowProc();
+
+ if(wParam)
+ {
+ LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam;
+ pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix();
+ }
+
+ return lRet;
+ }
+
+// Overrides
+ void UpdateLayout(BOOL bResizeBars = TRUE)
+ {
+ RECT rect = { 0 };
+ GetClientRect(&rect);
+
+ if (IsRibbonUI() && !IsRibbonHidden())
+ {
+ rect.top += GetRibbonHeight();
+ }
+ else if (!IsRibbonUI() && NeedWin7Fix())
+ {
+ ResetFrame();
+ }
+
+ // position bars and offset their dimensions
+ UpdateBarsPosition(rect, bResizeBars);
+
+ // resize client window
+ if(m_hWndClient != NULL)
+ ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ // Implementation
+ HBITMAP GetCommandBarBitmap(UINT nCmdID)
+ {
+ __if_exists (T::m_CmdBar)
+ {
+ ATLASSERT(RunTimeHelper::IsVista());
+ T* pT =static_cast<T*>(this);
+ int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID);
+ return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex];
+ }
+ __if_not_exists (T::m_CmdBar)
+ {
+ nCmdID; // avoid level 4 warning
+ return NULL;
+ }
+ }
+};
+
+// CRibbonFrameWindowImpl
+//
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
+class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CFrameWindowImpl<T, TBase, TWinTraits>>
+{ };
+
+// CRibbonMDIFrameWindowImpl
+//
+template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
+class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CMDIFrameWindowImpl<T, TBase, TWinTraits>>
+{ };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CRibbonPersist helper for RibbonUI persistency
+
+class CRibbonPersist
+{
+public:
+ CRibbonPersist(LPCWSTR sAppKey)
+ {
+ ATLASSERT(sAppKey && *sAppKey);
+ m_Key.Create(HKEY_CURRENT_USER, sAppKey);
+ ATLASSERT(m_Key.m_hKey);
+ }
+
+ CRegKeyEx m_Key;
+
+ LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL)
+ {
+ CRegKeyEx key;
+ const DWORD dwUI = bRibbonUI;
+
+ LONG lRet = key.Create(m_Key, L"Ribbon");
+ if(lRet != ERROR_SUCCESS)
+ return lRet;
+
+ lRet = key.SetDWORDValue(L"UI", dwUI);
+ if(lRet != ERROR_SUCCESS)
+ return lRet;
+
+ if (hgSettings != NULL)
+ {
+ LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings);
+ if (pVal != NULL)
+ {
+ lRet = key.SetBinaryValue(L"Settings", pVal, ::GlobalSize(hgSettings));
+ ::GlobalUnlock(hgSettings);
+ }
+ else
+ {
+ lRet = GetLastError();
+ }
+ }
+
+ return lRet;
+ }
+
+ LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings)
+ {
+ ATLASSERT(hgSettings == NULL);
+
+ CRegKeyEx key;
+
+ LONG lRet = key.Open(m_Key, L"Ribbon");
+ if(lRet != ERROR_SUCCESS)
+ return lRet;
+
+ DWORD dwUI = 0xffff;
+ lRet = key.QueryDWORDValue(L"UI", dwUI);
+ if(lRet == ERROR_SUCCESS)
+ bRibbonUI = dwUI == 1;
+ else
+ return lRet;
+
+ ULONG ulSize = 0;
+ lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize);
+ if (lRet == ERROR_SUCCESS)
+ {
+ ATLASSERT(ulSize != 0);
+
+ hgSettings = ::GlobalAlloc(GHND, ulSize);
+ if (hgSettings != NULL)
+ {
+ LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings);
+ if (pData != NULL)
+ {
+ lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize);
+ }
+ else
+ {
+ lRet = GetLastError();
+ ::GlobalFree(hgSettings);
+ hgSettings = NULL;
+ }
+ }
+ else
+ {
+ lRet = GetLastError();
+ }
+ }
+ return lRet;
+ }
+
+ LONG Delete()
+ {
+ return m_Key.DeleteSubKey(L"Ribbon");
+ }
+};
+
+} // namespace WTL
+
+#endif // __ATLRIBBON_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLSCRL_H__
+#define __ATLSCRL_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlscrl.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlscrl.h requires atlwin.h to be included first
+#endif
+
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ #include <zmouse.h>
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+
+#ifndef GET_WHEEL_DELTA_WPARAM
+ #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam))
+#endif
+
+#ifndef WM_MOUSEHWHEEL
+ #define WM_MOUSEHWHEEL 0x020E
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CScrollImpl<T>
+// CScrollWindowImpl<T, TBase, TWinTraits>
+// CMapScrollImpl<T>
+// CMapScrollWindowImpl<T, TBase, TWinTraits>
+// CFSBWindowT<TBase>
+// CZoomScrollImpl<T>
+// CZoomScrollWindowImpl<T, TBase, TWinTraits>
+// CScrollContainerImpl<T, TBase, TWinTraits>
+// CScrollContainer
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CScrollImpl - Provides scrolling support to any window
+
+// Scroll extended styles
+#define SCRL_SCROLLCHILDREN 0x00000001
+#define SCRL_ERASEBACKGROUND 0x00000002
+#define SCRL_NOTHUMBTRACKING 0x00000004
+#if (WINVER >= 0x0500)
+#define SCRL_SMOOTHSCROLL 0x00000008
+#endif // (WINVER >= 0x0500)
+#define SCRL_DISABLENOSCROLLV 0x00000010
+#define SCRL_DISABLENOSCROLLH 0x00000020
+#define SCRL_DISABLENOSCROLL (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH)
+
+
+template <class T>
+class CScrollImpl
+{
+public:
+ enum { uSCROLL_FLAGS = SW_INVALIDATE };
+
+ POINT m_ptOffset;
+ SIZE m_sizeAll;
+ SIZE m_sizeLine;
+ SIZE m_sizePage;
+ SIZE m_sizeClient;
+ int m_zDelta; // current wheel value
+ int m_nWheelLines; // number of lines to scroll on wheel
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ // Note that this message must be forwarded from a top level window
+ UINT m_uMsgMouseWheel; // MSH_MOUSEWHEEL
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ int m_zHDelta; // current horizontal wheel value
+ int m_nHWheelChars; // number of chars to scroll on horizontal wheel
+ UINT m_uScrollFlags;
+ DWORD m_dwExtendedStyle; // scroll specific extended styles
+
+// Constructor
+ CScrollImpl() : m_zDelta(0), m_nWheelLines(3),
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ m_uMsgMouseWheel(0U),
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ m_zHDelta(0), m_nHWheelChars(3),
+ m_uScrollFlags(0U), m_dwExtendedStyle(0)
+ {
+ m_ptOffset.x = 0;
+ m_ptOffset.y = 0;
+ m_sizeAll.cx = 0;
+ m_sizeAll.cy = 0;
+ m_sizePage.cx = 0;
+ m_sizePage.cy = 0;
+ m_sizeLine.cx = 0;
+ m_sizeLine.cy = 0;
+ m_sizeClient.cx = 0;
+ m_sizeClient.cy = 0;
+
+ SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND);
+ }
+
+// Attributes & Operations
+ DWORD GetScrollExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ // cache scroll flags
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0);
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0);
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ return dwPrevStyle;
+ }
+
+ // offset operations
+ void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ pT->AdjustScrollOffset(x, y);
+
+ int dx = m_ptOffset.x - x;
+ int dy = m_ptOffset.y - y;
+ m_ptOffset.x = x;
+ m_ptOffset.y = y;
+
+ // block: set horizontal scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_POS;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nPos = m_ptOffset.x;
+ pT->SetScrollInfo(SB_HORZ, &si, bRedraw);
+ }
+
+ // block: set vertical scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_POS;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nPos = m_ptOffset.y;
+ pT->SetScrollInfo(SB_VERT, &si, bRedraw);
+ }
+
+ // Move all children if needed
+ if(IsScrollingChildren() && (dx != 0 || dy != 0))
+ {
+ for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
+ {
+ RECT rect = { 0 };
+ ::GetWindowRect(hWndChild, &rect);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);
+ ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ }
+
+ if(bRedraw)
+ pT->Invalidate();
+ }
+
+ void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)
+ {
+ SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);
+ }
+
+ void GetScrollOffset(POINT& ptOffset) const
+ {
+ ptOffset = m_ptOffset;
+ }
+
+ // size operations
+ void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ m_sizeAll.cx = cx;
+ m_sizeAll.cy = cy;
+
+ int x = 0;
+ int y = 0;
+ if(!bResetOffset)
+ {
+ x = m_ptOffset.x;
+ y = m_ptOffset.y;
+ pT->AdjustScrollOffset(x, y);
+ }
+
+ int dx = m_ptOffset.x - x;
+ int dy = m_ptOffset.y - y;
+ m_ptOffset.x = x;
+ m_ptOffset.y = y;
+
+ // block: set horizontal scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nMin = 0;
+ si.nMax = m_sizeAll.cx - 1;
+ si.nPage = m_sizeClient.cx;
+ si.nPos = m_ptOffset.x;
+ pT->SetScrollInfo(SB_HORZ, &si, bRedraw);
+ }
+
+ // block: set vertical scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nMin = 0;
+ si.nMax = m_sizeAll.cy - 1;
+ si.nPage = m_sizeClient.cy;
+ si.nPos = m_ptOffset.y;
+ pT->SetScrollInfo(SB_VERT, &si, bRedraw);
+ }
+
+ // Move all children if needed
+ if(IsScrollingChildren() && (dx != 0 || dy != 0))
+ {
+ for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
+ {
+ RECT rect = { 0 };
+ ::GetWindowRect(hWndChild, &rect);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);
+ ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ }
+
+ SetScrollLine(0, 0);
+ SetScrollPage(0, 0);
+
+ if(bRedraw)
+ pT->Invalidate();
+ }
+
+ void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset);
+ }
+
+ void GetScrollSize(SIZE& sizeWnd) const
+ {
+ sizeWnd = m_sizeAll;
+ }
+
+ // line operations
+ void SetScrollLine(int cxLine, int cyLine)
+ {
+ ATLASSERT(cxLine >= 0 && cyLine >= 0);
+ ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);
+
+ m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100);
+ m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100);
+ }
+
+ void SetScrollLine(SIZE sizeLine)
+ {
+ SetScrollLine(sizeLine.cx, sizeLine.cy);
+ }
+
+ void GetScrollLine(SIZE& sizeLine) const
+ {
+ sizeLine = m_sizeLine;
+ }
+
+ // page operations
+ void SetScrollPage(int cxPage, int cyPage)
+ {
+ ATLASSERT(cxPage >= 0 && cyPage >= 0);
+ ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);
+
+ m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10);
+ m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10);
+ }
+
+ void SetScrollPage(SIZE sizePage)
+ {
+ SetScrollPage(sizePage.cx, sizePage.cy);
+ }
+
+ void GetScrollPage(SIZE& sizePage) const
+ {
+ sizePage = m_sizePage;
+ }
+
+ // commands
+ void ScrollLineDown()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollLineUp()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollPageDown()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollPageUp()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollTop()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollBottom()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ }
+
+ void ScrollLineRight()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ void ScrollLineLeft()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ void ScrollPageRight()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ void ScrollPageLeft()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ void ScrollAllLeft()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ void ScrollAllRight()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ }
+
+ // scroll to make point/view/window visible
+ void ScrollToView(POINT pt)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ RECT rect = { pt.x, pt.y, pt.x, pt.y };
+ pT->ScrollToView(rect);
+ }
+
+ void ScrollToView(RECT& rect)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ RECT rcClient = { 0 };
+ pT->GetClientRect(&rcClient);
+
+ int x = m_ptOffset.x;
+ if(rect.left < m_ptOffset.x)
+ x = rect.left;
+ else if(rect.right > (m_ptOffset.x + rcClient.right))
+ x = rect.right - rcClient.right;
+
+ int y = m_ptOffset.y;
+ if(rect.top < m_ptOffset.y)
+ y = rect.top;
+ else if(rect.bottom > (m_ptOffset.y + rcClient.bottom))
+ y = rect.bottom - rcClient.bottom;
+
+ SetScrollOffset(x, y);
+ }
+
+ void ScrollToView(HWND hWnd)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ RECT rect = { 0 };
+ ::GetWindowRect(hWnd, &rect);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2);
+ ScrollToView(rect);
+ }
+
+ BEGIN_MSG_MAP(CScrollImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_VSCROLL, OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+#endif // !_WIN32_WCE
+ // standard scroll commands
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ GetSystemSettings();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ return 0;
+ }
+
+ LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ return 0;
+ }
+
+ LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)
+ uMsg;
+ int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);
+#else
+ int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam;
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE))
+ int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN);
+ m_zDelta += zDelta; // cumulative
+ int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines;
+ if(m_sizeAll.cy > m_sizeClient.cy)
+ {
+ for(int i = 0; i < zTotal; i += WHEEL_DELTA)
+ {
+ pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
+ pT->UpdateWindow();
+ }
+ }
+ else // can't scroll vertically, scroll horizontally
+ {
+ for(int i = 0; i < zTotal; i += WHEEL_DELTA)
+ {
+ pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ pT->UpdateWindow();
+ }
+ }
+ m_zDelta %= WHEEL_DELTA;
+
+ return 0;
+ }
+
+ LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);
+ int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT);
+ m_zHDelta += zDelta; // cumulative
+ int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars;
+ if(m_sizeAll.cx > m_sizeClient.cx)
+ {
+ for(int i = 0; i < zTotal; i += WHEEL_DELTA)
+ {
+ pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
+ pT->UpdateWindow();
+ }
+ }
+ m_zHDelta %= WHEEL_DELTA;
+
+ return 0;
+ }
+
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ GetSystemSettings();
+ return 0;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ m_sizeClient.cx = GET_X_LPARAM(lParam);
+ m_sizeClient.cy = GET_Y_LPARAM(lParam);
+
+ // block: set horizontal scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = m_sizeAll.cx - 1;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nPage = m_sizeClient.cx;
+ si.nPos = m_ptOffset.x;
+ pT->SetScrollInfo(SB_HORZ, &si, TRUE);
+ }
+
+ // block: set vertical scroll bar
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO) };
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = m_sizeAll.cy - 1;
+ if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nPage = m_sizeClient.cy;
+ si.nPos = m_ptOffset.y;
+ pT->SetScrollInfo(SB_VERT, &si, TRUE);
+ }
+
+ int x = m_ptOffset.x;
+ int y = m_ptOffset.y;
+ if(pT->AdjustScrollOffset(x, y))
+ {
+ // Children will be moved in SetScrollOffset, if needed
+ pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN));
+ SetScrollOffset(x, y, FALSE);
+ }
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ if(wParam != NULL)
+ {
+ CDCHandle dc = (HDC)wParam;
+ POINT ptViewportOrg = { 0, 0 };
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
+ pT->DoPaint(dc);
+ dc.SetViewportOrg(ptViewportOrg);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
+ pT->DoPaint(dc.m_hDC);
+ }
+ return 0;
+ }
+
+ // scrolling handlers
+ LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollLineUp();
+ return 0;
+ }
+
+ LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollLineDown();
+ return 0;
+ }
+
+ LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollPageUp();
+ return 0;
+ }
+
+ LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollPageDown();
+ return 0;
+ }
+
+ LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollTop();
+ return 0;
+ }
+
+ LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollBottom();
+ return 0;
+ }
+
+ LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollLineLeft();
+ return 0;
+ }
+
+ LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollLineRight();
+ return 0;
+ }
+
+ LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollPageLeft();
+ return 0;
+ }
+
+ LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollPageRight();
+ return 0;
+ }
+
+ LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollAllLeft();
+ return 0;
+ }
+
+ LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ ScrollAllRight();
+ return 0;
+ }
+
+// Overrideables
+ void DoPaint(CDCHandle /*dc*/)
+ {
+ // must be implemented in a derived class
+ ATLASSERT(FALSE);
+ }
+
+// Implementation
+ void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rect = { 0 };
+ pT->GetClientRect(&rect);
+ int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right;
+ int cxyMax = cxySizeAll - cxyClient;
+
+ if(cxyMax < 0) // can't scroll, client area is bigger
+ return;
+
+ bool bUpdate = true;
+ int cxyScroll = 0;
+
+ switch(nScrollCode)
+ {
+ case SB_TOP: // top or all left
+ cxyScroll = cxyOffset;
+ cxyOffset = 0;
+ break;
+ case SB_BOTTOM: // bottom or all right
+ cxyScroll = cxyOffset - cxyMax;
+ cxyOffset = cxyMax;
+ break;
+ case SB_LINEUP: // line up or line left
+ if(cxyOffset >= cxySizeLine)
+ {
+ cxyScroll = cxySizeLine;
+ cxyOffset -= cxySizeLine;
+ }
+ else
+ {
+ cxyScroll = cxyOffset;
+ cxyOffset = 0;
+ }
+ break;
+ case SB_LINEDOWN: // line down or line right
+ if(cxyOffset < cxyMax - cxySizeLine)
+ {
+ cxyScroll = -cxySizeLine;
+ cxyOffset += cxySizeLine;
+ }
+ else
+ {
+ cxyScroll = cxyOffset - cxyMax;
+ cxyOffset = cxyMax;
+ }
+ break;
+ case SB_PAGEUP: // page up or page left
+ if(cxyOffset >= cxySizePage)
+ {
+ cxyScroll = cxySizePage;
+ cxyOffset -= cxySizePage;
+ }
+ else
+ {
+ cxyScroll = cxyOffset;
+ cxyOffset = 0;
+ }
+ break;
+ case SB_PAGEDOWN: // page down or page right
+ if(cxyOffset < cxyMax - cxySizePage)
+ {
+ cxyScroll = -cxySizePage;
+ cxyOffset += cxySizePage;
+ }
+ else
+ {
+ cxyScroll = cxyOffset - cxyMax;
+ cxyOffset = cxyMax;
+ }
+ break;
+ case SB_THUMBTRACK:
+ if(IsNoThumbTracking())
+ break;
+ // else fall through
+ case SB_THUMBPOSITION:
+ {
+ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS };
+ if(pT->GetScrollInfo(nType, &si))
+ {
+ cxyScroll = cxyOffset - si.nTrackPos;
+ cxyOffset = si.nTrackPos;
+ }
+ }
+ break;
+ case SB_ENDSCROLL:
+ default:
+ bUpdate = false;
+ break;
+ }
+
+ if(bUpdate && cxyScroll != 0)
+ {
+ pT->SetScrollPos(nType, cxyOffset, TRUE);
+ if(nType == SB_VERT)
+ pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags);
+ else
+ pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags);
+ }
+ }
+
+ static int CalcLineOrPage(int nVal, int nMax, int nDiv)
+ {
+ if(nVal == 0)
+ {
+ nVal = nMax / nDiv;
+ if(nVal < 1)
+ nVal = 1;
+ }
+ else if(nVal > nMax)
+ {
+ nVal = nMax;
+ }
+
+ return nVal;
+ }
+
+ bool AdjustScrollOffset(int& x, int& y)
+ {
+ int xOld = x;
+ int yOld = y;
+
+ int cxMax = m_sizeAll.cx - m_sizeClient.cx;
+ if(x > cxMax)
+ x = (cxMax >= 0) ? cxMax : 0;
+ else if(x < 0)
+ x = 0;
+
+ int cyMax = m_sizeAll.cy - m_sizeClient.cy;
+ if(y > cyMax)
+ y = (cyMax >= 0) ? cyMax : 0;
+ else if(y < 0)
+ y = 0;
+
+ return (x != xOld || y != yOld);
+ }
+
+ void GetSystemSettings()
+ {
+#ifndef _WIN32_WCE
+#ifndef SPI_GETWHEELSCROLLLINES
+ const UINT SPI_GETWHEELSCROLLLINES = 104;
+#endif // !SPI_GETWHEELSCROLLLINES
+ ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0);
+
+#ifndef SPI_GETWHEELSCROLLCHARS
+ const UINT SPI_GETWHEELSCROLLCHARS = 0x006C;
+#endif // !SPI_GETWHEELSCROLLCHARS
+ ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0);
+
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ if(m_uMsgMouseWheel != 0)
+ m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL);
+
+ HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
+ if(::IsWindow(hWndWheel))
+ {
+ UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
+ if(uMsgScrollLines != 0)
+ m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L);
+ }
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+#endif // !_WIN32_WCE
+ }
+
+ bool IsScrollingChildren() const
+ {
+ return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0;
+ }
+
+ bool IsErasingBackground() const
+ {
+ return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0;
+ }
+
+ bool IsNoThumbTracking() const
+ {
+ return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0;
+ }
+
+#if (WINVER >= 0x0500)
+ bool IsSmoothScroll() const
+ {
+ return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0;
+ }
+#endif // (WINVER >= 0x0500)
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScrollWindowImpl - Implements a scrollable window
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CScrollImpl< T >
+{
+public:
+ BEGIN_MSG_MAP(CScrollWindowImpl)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
+ MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint)
+#endif // !_WIN32_WCE
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMapScrollImpl - Provides mapping and scrolling support to any window
+
+#ifndef _WIN32_WCE
+
+template <class T>
+class CMapScrollImpl : public CScrollImpl< T >
+{
+public:
+ int m_nMapMode;
+ RECT m_rectLogAll;
+ SIZE m_sizeLogLine;
+ SIZE m_sizeLogPage;
+
+// Constructor
+ CMapScrollImpl() : m_nMapMode(MM_TEXT)
+ {
+ ::SetRectEmpty(&m_rectLogAll);
+ m_sizeLogPage.cx = 0;
+ m_sizeLogPage.cy = 0;
+ m_sizeLogLine.cx = 0;
+ m_sizeLogLine.cy = 0;
+ }
+
+// Attributes & Operations
+ // mapping mode operations
+ void SetScrollMapMode(int nMapMode)
+ {
+ ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE);
+ m_nMapMode = nMapMode;
+ }
+
+ int GetScrollMapMode() const
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ return m_nMapMode;
+ }
+
+ // offset operations
+ void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ POINT ptOff = { x, y };
+ // block: convert logical to device units
+ {
+ CWindowDC dc(NULL);
+ dc.SetMapMode(m_nMapMode);
+ dc.LPtoDP(&ptOff);
+ }
+ CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw);
+ }
+
+ void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)
+ {
+ SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);
+ }
+
+ void GetScrollOffset(POINT& ptOffset) const
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ ptOffset = m_ptOffset;
+ // block: convert device to logical units
+ {
+ CWindowDC dc(NULL);
+ dc.SetMapMode(m_nMapMode);
+ dc.DPtoLP(&ptOffset);
+ }
+ }
+
+ // size operations
+ void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ ATLASSERT(xMax > xMin && yMax > yMin);
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+
+ ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax);
+
+ SIZE sizeAll = { 0 };
+ sizeAll.cx = xMax - xMin + 1;
+ sizeAll.cy = yMax - yMin + 1;
+ // block: convert logical to device units
+ {
+ CWindowDC dc(NULL);
+ dc.SetMapMode(m_nMapMode);
+ dc.LPtoDP(&sizeAll);
+ }
+ CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);
+ SetScrollLine(0, 0);
+ SetScrollPage(0, 0);
+ }
+
+ void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset);
+ }
+
+ void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset);
+ }
+
+ void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset);
+ }
+
+ void GetScrollSize(RECT& rcScroll) const
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ rcScroll = m_rectLogAll;
+ }
+
+ // line operations
+ void SetScrollLine(int cxLine, int cyLine)
+ {
+ ATLASSERT(cxLine >= 0 && cyLine >= 0);
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+
+ m_sizeLogLine.cx = cxLine;
+ m_sizeLogLine.cy = cyLine;
+ SIZE sizeLine = m_sizeLogLine;
+ // block: convert logical to device units
+ {
+ CWindowDC dc(NULL);
+ dc.SetMapMode(m_nMapMode);
+ dc.LPtoDP(&sizeLine);
+ }
+ CScrollImpl< T >::SetScrollLine(sizeLine);
+ }
+
+ void SetScrollLine(SIZE sizeLine)
+ {
+ SetScrollLine(sizeLine.cx, sizeLine.cy);
+ }
+
+ void GetScrollLine(SIZE& sizeLine) const
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ sizeLine = m_sizeLogLine;
+ }
+
+ // page operations
+ void SetScrollPage(int cxPage, int cyPage)
+ {
+ ATLASSERT(cxPage >= 0 && cyPage >= 0);
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+
+ m_sizeLogPage.cx = cxPage;
+ m_sizeLogPage.cy = cyPage;
+ SIZE sizePage = m_sizeLogPage;
+ // block: convert logical to device units
+ {
+ CWindowDC dc(NULL);
+ dc.SetMapMode(m_nMapMode);
+ dc.LPtoDP(&sizePage);
+ }
+ CScrollImpl< T >::SetScrollPage(sizePage);
+ }
+
+ void SetScrollPage(SIZE sizePage)
+ {
+ SetScrollPage(sizePage.cx, sizePage.cy);
+ }
+
+ void GetScrollPage(SIZE& sizePage) const
+ {
+ ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
+ sizePage = m_sizeLogPage;
+ }
+
+ BEGIN_MSG_MAP(CMapScrollImpl)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ if(wParam != NULL)
+ {
+ CDCHandle dc = (HDC)wParam;
+ int nMapModeSav = dc.GetMapMode();
+ dc.SetMapMode(m_nMapMode);
+ POINT ptViewportOrg = { 0, 0 };
+ if(m_nMapMode == MM_TEXT)
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
+ else
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg);
+ POINT ptWindowOrg = { 0, 0 };
+ dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg);
+
+ pT->DoPaint(dc);
+
+ dc.SetMapMode(nMapModeSav);
+ dc.SetViewportOrg(ptViewportOrg);
+ dc.SetWindowOrg(ptWindowOrg);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ dc.SetMapMode(m_nMapMode);
+ if(m_nMapMode == MM_TEXT)
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
+ else
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy);
+ dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top);
+ pT->DoPaint(dc.m_hDC);
+ }
+ return 0;
+ }
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMapScrollWindowImpl - Implements scrolling window with mapping
+
+#ifndef _WIN32_WCE
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T >
+{
+public:
+ BEGIN_MSG_MAP(CMapScrollWindowImpl)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
+ MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support
+
+#if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+template <class TBase = ATL::CWindow>
+class CFSBWindowT : public TBase, public CFlatScrollBarImpl<CFSBWindowT< TBase > >
+{
+public:
+// Constructors
+ CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CFSBWindowT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+// CWindow overrides that use flat scroll bar API
+// (only those methods that are used by scroll window classes)
+ int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return FlatSB_SetScrollPos(nBar, nPos, bRedraw);
+ }
+
+ BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return FlatSB_GetScrollInfo(nBar, lpScrollInfo);
+ }
+
+ BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw);
+ }
+};
+
+typedef CFSBWindowT<ATL::CWindow> CFSBWindow;
+
+#endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CZoomScrollImpl - Provides zooming and scrolling support to any window
+
+#ifndef _WIN32_WCE
+
+// The zoom modes that can be set with the SetZoomMode method
+enum
+{
+ ZOOMMODE_OFF,
+ ZOOMMODE_IN, // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged.
+ ZOOMMODE_OUT // If left mouse button clicked, zoom out on point clicked.
+};
+
+// Notification to parent that zoom scale changed as a result of user mouse action.
+#define ZSN_ZOOMCHANGED (NM_FIRST - 50)
+
+template <class T>
+class CZoomScrollImpl : public CScrollImpl< T >
+{
+public:
+ enum { m_cxyMinZoomRect = 12 }; // min rect size to zoom in on rect.
+
+// Data members
+ SIZE m_sizeLogAll;
+ SIZE m_sizeLogLine;
+ SIZE m_sizeLogPage;
+ float m_fZoomScale;
+ float m_fZoomScaleMin;
+ float m_fZoomDelta; // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click.
+ int m_nZoomMode;
+ RECT m_rcTrack;
+ bool m_bTracking;
+
+// Constructor
+ CZoomScrollImpl():
+ m_fZoomScale(1.0),
+ m_fZoomScaleMin(0.5),
+ m_fZoomDelta(0.5),
+ m_nZoomMode(ZOOMMODE_OFF),
+ m_bTracking(false)
+ {
+ m_sizeLogAll.cx = 0;
+ m_sizeLogAll.cy = 0;
+ m_sizeLogPage.cx = 0;
+ m_sizeLogPage.cy = 0;
+ m_sizeLogLine.cx = 0;
+ m_sizeLogLine.cy = 0;
+ ::SetRectEmpty(&m_rcTrack);
+ }
+
+// Attributes & Operations
+
+ // size operations
+ void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ ATLASSERT(cxLog >= 0 && cyLog >= 0);
+
+ // Set up the defaults
+ if (cxLog == 0 && cyLog == 0)
+ {
+ cxLog = 1;
+ cyLog = 1;
+ }
+
+ m_sizeLogAll.cx = cxLog;
+ m_sizeLogAll.cy = cyLog;
+ SIZE sizeAll = { 0 };
+ sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale);
+ sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale);
+
+ CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);
+ }
+
+ void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true)
+ {
+ SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset);
+ }
+
+ void GetScrollSize(SIZE& sizeLog) const
+ {
+ sizeLog = m_sizeLogAll;
+ }
+
+ // line operations
+ void SetScrollLine(int cxLogLine, int cyLogLine)
+ {
+ ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0);
+
+ m_sizeLogLine.cx = cxLogLine;
+ m_sizeLogLine.cy = cyLogLine;
+
+ SIZE sizeLine = { 0 };
+ sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale);
+ sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale);
+ CScrollImpl< T >::SetScrollLine(sizeLine);
+ }
+
+ void SetScrollLine(SIZE sizeLogLine)
+ {
+ SetScrollLine(sizeLogLine.cx, sizeLogLine.cy);
+ }
+
+ void GetScrollLine(SIZE& sizeLogLine) const
+ {
+ sizeLogLine = m_sizeLogLine;
+ }
+
+ // page operations
+ void SetScrollPage(int cxLogPage, int cyLogPage)
+ {
+ ATLASSERT(cxLogPage >= 0 && cyLogPage >= 0);
+
+ m_sizeLogPage.cx = cxLogPage;
+ m_sizeLogPage.cy = cyLogPage;
+
+ SIZE sizePage = { 0 };
+ sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale);
+ sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale);
+
+ CScrollImpl< T >::SetScrollPage(sizePage);
+ }
+
+ void SetScrollPage(SIZE sizeLogPage)
+ {
+ SetScrollPage(sizeLogPage.cx, sizeLogPage.cy);
+ }
+
+ void GetScrollPage(SIZE& sizeLogPage) const
+ {
+ sizeLogPage = m_sizeLogPage;
+ }
+
+ void SetZoomScale(float fZoomScale)
+ {
+ ATLASSERT(fZoomScale > 0);
+
+ if(fZoomScale > 0 && fZoomScale >= m_fZoomScaleMin)
+ m_fZoomScale = fZoomScale;
+ }
+
+ float GetZoomScale() const
+ {
+ return m_fZoomScale;
+ }
+
+ void SetZoomScaleMin(float fZoomScaleMin)
+ {
+ m_fZoomScaleMin = fZoomScaleMin;
+ }
+
+ float GetZoomScaleMin() const
+ {
+ return m_fZoomScaleMin;
+ }
+
+ void SetZoomDelta(float fZoomDelta)
+ {
+ ATLASSERT(fZoomDelta >= 0);
+
+ if(fZoomDelta >= 0)
+ m_fZoomDelta = fZoomDelta;
+ }
+
+ float GetZoomDelta() const
+ {
+ return m_fZoomDelta;
+ }
+
+ void SetZoomMode(int nZoomMode)
+ {
+ m_nZoomMode = nZoomMode;
+ }
+
+ int GetZoomMode() const
+ {
+ return m_nZoomMode;
+ }
+
+ void Zoom(int x, int y, float fZoomScale)
+ {
+ if(fZoomScale <= 0)
+ return;
+
+ fZoomScale = max(fZoomScale, m_fZoomScaleMin);
+
+ T* pT = static_cast<T*>(this);
+ POINT pt = { x, y };
+ if(!pT->PtInDevRect(pt))
+ return;
+
+ pT->ViewDPtoLP(&pt);
+ pT->Zoom(fZoomScale, false);
+ pT->CenterOnLogicalPoint(pt);
+ }
+
+ void Zoom(POINT pt, float fZoomScale)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Zoom(pt.x, pt.y, fZoomScale);
+ }
+
+ void Zoom(RECT& rc)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rcZoom = rc;
+ pT->NormalizeRect(rcZoom);
+ SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top };
+ POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 };
+ if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect)
+ {
+ pT->Zoom(pt, m_fZoomScale + m_fZoomDelta);
+ return;
+ }
+
+ ATLASSERT(size.cx > 0 && size.cy > 0);
+
+ float fScaleH = (float)(m_sizeClient.cx + 1) / (float)size.cx;
+ float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy;
+ float fZoomScale = min(fScaleH, fScaleV) * m_fZoomScale;
+ pT->Zoom(pt, fZoomScale);
+ }
+
+ void Zoom(float fZoomScale, bool bCenter = true)
+ {
+ if(fZoomScale <= 0)
+ return;
+
+ fZoomScale = max(fZoomScale, m_fZoomScaleMin);
+
+
+ T* pT = static_cast<T*>(this);
+ POINT pt = { 0 };
+ if(bCenter)
+ {
+ RECT rc;
+ ::GetClientRect(pT->m_hWnd, &rc);
+ pt.x = rc.right / 2;
+ pt.y = rc.bottom / 2;
+ pT->ViewDPtoLP(&pt);
+ }
+
+ // Modify the Viewport extent
+ m_fZoomScale = fZoomScale;
+ SIZE sizeAll = { 0 };
+ sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale);
+ sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale);
+
+ // Update scroll bars and window
+ CScrollImpl< T >::SetScrollSize(sizeAll);
+
+ if(bCenter)
+ pT->CenterOnLogicalPoint(pt);
+ }
+
+ // Helper functions
+ void PrepareDC(CDCHandle dc)
+ {
+ ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);
+ dc.SetMapMode(MM_ANISOTROPIC);
+ dc.SetWindowExt(m_sizeLogAll);
+ dc.SetViewportExt(m_sizeAll);
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
+ }
+
+ void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1)
+ {
+ ATLASSERT(lpPoints);
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ CWindowDC dc(pT->m_hWnd);
+ pT->PrepareDC(dc.m_hDC);
+ dc.DPtoLP(lpPoints, nCount);
+ }
+
+ void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1)
+ {
+ ATLASSERT(lpPoints);
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+
+ CWindowDC dc(pT->m_hWnd);
+ pT->PrepareDC(dc.m_hDC);
+ dc.LPtoDP(lpPoints, nCount);
+ }
+
+ void ClientToDevice(POINT &pt)
+ {
+ pt.x += m_ptOffset.x;
+ pt.y += m_ptOffset.y;
+ }
+
+ void DeviceToClient(POINT &pt)
+ {
+ pt.x -= m_ptOffset.x;
+ pt.y -= m_ptOffset.y;
+ }
+
+ void CenterOnPoint(POINT pt)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rect;
+ pT->GetClientRect(&rect);
+
+ int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x;
+ if(xOfs < 0)
+ {
+ xOfs = 0;
+ }
+ else
+ {
+ int xMax = max((int)(m_sizeAll.cx - rect.right), 0);
+ if(xOfs > xMax)
+ xOfs = xMax;
+ }
+
+ int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y;
+ if(yOfs < 0)
+ {
+ yOfs = 0;
+ }
+ else
+ {
+ int yMax = max((int)(m_sizeAll.cy - rect.bottom), 0);
+ if(yOfs > yMax)
+ yOfs = yMax;
+ }
+
+ CScrollImpl< T >::SetScrollOffset(xOfs, yOfs);
+ }
+
+ void CenterOnLogicalPoint(POINT ptLog)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->ViewLPtoDP(&ptLog);
+ pT->DeviceToClient(ptLog);
+ pT->CenterOnPoint(ptLog);
+ }
+
+ BOOL PtInDevRect(POINT pt)
+ {
+ RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy };
+ ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y);
+ return ::PtInRect(&rc, pt);
+ }
+
+ void NormalizeRect(RECT& rc)
+ {
+ if(rc.left > rc.right)
+ {
+ int r = rc.right;
+ rc.right = rc.left;
+ rc.left = r;
+ }
+ if(rc.top > rc.bottom)
+ {
+ int b = rc.bottom;
+ rc.bottom = rc.top;
+ rc.top = b;
+ }
+ }
+
+ void DrawTrackRect()
+ {
+ T* pT = static_cast<T*>(this);
+ const SIZE sizeLines = { 2, 2 };
+ RECT rc = m_rcTrack;
+ pT->NormalizeRect(rc);
+ if(!::IsRectEmpty(&rc))
+ {
+ ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2);
+ CWindowDC dc(NULL);
+ dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines);
+ }
+ }
+
+ void NotifyParentZoomChanged()
+ {
+ T* pT = static_cast<T*>(this);
+ int nId = pT->GetDlgCtrlID();
+ NMHDR nmhdr = { pT->m_hWnd, nId, ZSN_ZOOMCHANGED };
+ ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr);
+ }
+
+ BEGIN_MSG_MAP(CZoomScrollImpl)
+ MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ ATLASSERT(m_sizeLogAll.cx >= 0 && m_sizeLogAll.cy >= 0);
+ ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);
+
+ if(wParam != NULL)
+ {
+ CDCHandle dc = (HDC)wParam;
+ int nMapModeSav = dc.GetMapMode();
+ dc.SetMapMode(MM_ANISOTROPIC);
+ SIZE szWindowExt = { 0, 0 };
+ dc.SetWindowExt(m_sizeLogAll, &szWindowExt);
+ SIZE szViewportExt = { 0, 0 };
+ dc.SetViewportExt(m_sizeAll, &szViewportExt);
+ POINT ptViewportOrg = { 0, 0 };
+ dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
+
+ pT->DoPaint(dc);
+
+ dc.SetMapMode(nMapModeSav);
+ dc.SetWindowExt(szWindowExt);
+ dc.SetViewportExt(szViewportExt);
+ dc.SetViewportOrg(ptViewportOrg);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ pT->PrepareDC(dc.m_hDC);
+ pT->DoPaint(dc.m_hDC);
+ }
+ return 0;
+ }
+
+ LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking)
+ {
+ T* pT = static_cast<T*>(this);
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ if(pT->PtInDevRect(pt))
+ {
+ pT->SetCapture();
+ m_bTracking = true;
+ ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y);
+ }
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ if(m_bTracking)
+ {
+ T* pT = static_cast<T*>(this);
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ if(pT->PtInDevRect(pt))
+ {
+ pT->DrawTrackRect();
+ m_rcTrack.right = pt.x;
+ m_rcTrack.bottom = pt.y;
+ pT->DrawTrackRect();
+ }
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ ::ReleaseCapture();
+ if(m_nZoomMode == ZOOMMODE_OUT)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta);
+ pT->NotifyParentZoomChanged();
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_bTracking)
+ {
+ m_bTracking = false;
+ T* pT = static_cast<T*>(this);
+ pT->DrawTrackRect();
+ pT->Zoom(m_rcTrack);
+ pT->NotifyParentZoomChanged();
+ ::SetRectEmpty(&m_rcTrack);
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF)
+ {
+ T* pT = static_cast<T*>(this);
+ if((HWND)wParam == pT->m_hWnd)
+ {
+ DWORD dwPos = ::GetMessagePos();
+ POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
+ pT->ScreenToClient(&pt);
+ if(pT->PtInDevRect(pt))
+ {
+ ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
+ return 1;
+ }
+ }
+ }
+ bHandled = FALSE;
+ return 0;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CZoomScrollWindowImpl - Implements scrolling window with zooming
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >
+{
+public:
+ BEGIN_MSG_MAP(CZoomScrollWindowImpl)
+ MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)
+ MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
+ MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
+#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
+#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
+ MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
+ MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
+ MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
+ ALT_MSG_MAP(1)
+ COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
+ COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
+ COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
+ COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
+ COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
+ END_MSG_MAP()
+};
+
+#endif // !_WIN32_WCE
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScrollContainer
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits >
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, 0, -1)
+
+ typedef CScrollWindowImpl< T, TBase, TWinTraits > _baseClass;
+
+// Data members
+ ATL::CWindow m_wndClient;
+ bool m_bAutoSizeClient;
+ bool m_bDrawEdgeIfEmpty;
+
+// Constructor
+ CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false)
+ {
+ // Set CScrollWindowImpl extended style
+ SetScrollExtendedStyle(SCRL_SCROLLCHILDREN);
+ }
+
+// Attributes
+ HWND GetClient() const
+ {
+ return m_wndClient;
+ }
+
+ HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ HWND hWndOldClient = m_wndClient;
+ m_wndClient = hWndClient;
+
+ SetRedraw(FALSE);
+ SetScrollSize(1, 1, FALSE);
+
+ if(m_wndClient.m_hWnd != NULL)
+ {
+ m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+
+ if(bClientSizeAsMin)
+ {
+ RECT rect = { 0 };
+ m_wndClient.GetWindowRect(&rect);
+ if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0)
+ SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE);
+ }
+
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+ }
+
+ SetRedraw(TRUE);
+ RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);
+
+ return hWndOldClient;
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CScrollContainerImpl)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ CHAIN_MSG_MAP(_baseClass)
+ FORWARD_NOTIFICATIONS()
+ ALT_MSG_MAP(1)
+ CHAIN_MSG_MAP_ALT(_baseClass, 1)
+ END_MSG_MAP()
+
+ LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(m_wndClient.m_hWnd != NULL)
+ m_wndClient.SetFocus();
+
+ return 0;
+ }
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background needed
+ }
+
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ BOOL bTmp = TRUE;
+ LRESULT lRet = _baseClass::OnSize(uMsg, wParam, lParam, bTmp);
+
+ T* pT = static_cast<T*>(this);
+ pT->UpdateLayout();
+
+ return lRet;
+ }
+
+// Overrides for CScrollWindowImpl
+ void DoPaint(CDCHandle dc)
+ {
+ if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rect = { 0 };
+ pT->GetContainerRect(rect);
+
+ if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL)
+ dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+
+ dc.FillRect(&rect, COLOR_APPWORKSPACE);
+ }
+ }
+
+ void ScrollToView(POINT pt)
+ {
+ CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt);
+ }
+
+ void ScrollToView(RECT& rect)
+ {
+ CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect);
+ }
+
+ void ScrollToView(HWND hWnd) // client window coordinates
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ ATLASSERT(m_wndClient.IsWindow());
+
+ RECT rect = { 0 };
+ ::GetWindowRect(hWnd, &rect);
+ ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2);
+ ScrollToView(rect);
+ }
+
+// Implementation - overrideable methods
+ void UpdateLayout()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+
+ if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ RECT rect = { 0 };
+ pT->GetContainerRect(rect);
+
+ m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);
+ }
+ else
+ {
+ Invalidate();
+ }
+ }
+
+ void GetContainerRect(RECT& rect)
+ {
+ GetClientRect(&rect);
+
+ if(rect.right < m_sizeAll.cx)
+ rect.right = m_sizeAll.cx;
+
+ if(rect.bottom < m_sizeAll.cy)
+ rect.bottom = m_sizeAll.cy;
+ }
+};
+
+class CScrollContainer : public CScrollContainerImpl<CScrollContainer>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1)
+};
+
+}; // namespace WTL
+
+#endif // __ATLSCRL_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLSPLIT_H__
+#define __ATLSPLIT_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlsplit.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlsplit.h requires atlwin.h to be included first
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CSplitterImpl<T, t_bVertical>
+// CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
+// CSplitterWindowT<t_bVertical>
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CSplitterImpl - Provides splitter support to any window
+
+// Splitter panes constants
+#define SPLIT_PANE_LEFT 0
+#define SPLIT_PANE_RIGHT 1
+#define SPLIT_PANE_TOP SPLIT_PANE_LEFT
+#define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT
+#define SPLIT_PANE_NONE -1
+
+// Splitter extended styles
+#define SPLIT_PROPORTIONAL 0x00000001
+#define SPLIT_NONINTERACTIVE 0x00000002
+#define SPLIT_RIGHTALIGNED 0x00000004
+#define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED
+#define SPLIT_GRADIENTBAR 0x00000008
+#define SPLIT_FIXEDBARSIZE 0x00000010
+
+// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
+// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL
+
+
+template <class T, bool t_bVertical = true>
+class CSplitterImpl
+{
+public:
+ enum { m_nPanesCount = 2, m_nPropMax = 10000 };
+
+ HWND m_hWndPane[m_nPanesCount];
+ RECT m_rcSplitter;
+ int m_xySplitterPos;
+ int m_nDefActivePane;
+ int m_cxySplitBar; // splitter bar width/height
+ static HCURSOR m_hCursor;
+ int m_cxyMin; // minimum pane size
+ int m_cxyBarEdge; // splitter bar edge
+ bool m_bFullDrag;
+ int m_cxyDragOffset;
+ int m_nProportionalPos;
+ bool m_bUpdateProportionalPos;
+ DWORD m_dwExtendedStyle; // splitter specific extended styles
+ int m_nSinglePane; // single pane mode
+
+// Constructor
+ CSplitterImpl() :
+ m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE),
+ m_cxySplitBar(4), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true),
+ m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
+ m_dwExtendedStyle(SPLIT_PROPORTIONAL),
+ m_nSinglePane(SPLIT_PANE_NONE)
+ {
+ m_hWndPane[SPLIT_PANE_LEFT] = NULL;
+ m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
+
+ ::SetRectEmpty(&m_rcSplitter);
+
+ if(m_hCursor == NULL)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n"));
+ ATLASSERT(FALSE);
+ return;
+ }
+
+ if(m_hCursor == NULL)
+ m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
+
+ lock.Unlock();
+ }
+ }
+
+// Attributes
+ void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
+ {
+ if(lpRect == NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->GetClientRect(&m_rcSplitter);
+ }
+ else
+ {
+ m_rcSplitter = *lpRect;
+ }
+
+ if(IsProportional())
+ UpdateProportionalPos();
+ else if(IsRightAligned())
+ UpdateRightAlignPos();
+
+ if(bUpdate)
+ UpdateSplitterLayout();
+ }
+
+ void GetSplitterRect(LPRECT lpRect) const
+ {
+ ATLASSERT(lpRect != NULL);
+ *lpRect = m_rcSplitter;
+ }
+
+ bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
+ {
+ if(xyPos == -1) // -1 == middle
+ {
+ if(t_bVertical)
+ xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
+ else
+ xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
+ }
+
+ // Adjust if out of valid range
+ int cxyMax = 0;
+ if(t_bVertical)
+ cxyMax = m_rcSplitter.right - m_rcSplitter.left;
+ else
+ cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
+
+ if(xyPos < m_cxyMin + m_cxyBarEdge)
+ xyPos = m_cxyMin;
+ else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
+ xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
+
+ // Set new position and update if requested
+ bool bRet = (m_xySplitterPos != xyPos);
+ m_xySplitterPos = xyPos;
+
+ if(m_bUpdateProportionalPos)
+ {
+ if(IsProportional())
+ StoreProportionalPos();
+ else if(IsRightAligned())
+ StoreRightAlignPos();
+ }
+ else
+ {
+ m_bUpdateProportionalPos = true;
+ }
+
+ if(bUpdate && bRet)
+ UpdateSplitterLayout();
+
+ return bRet;
+ }
+
+ void SetSplitterPosPct(int nPct, bool bUpdate = true)
+ {
+ ATLASSERT(nPct >= 0 && nPct <= 100);
+
+ m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
+ UpdateProportionalPos();
+
+ if(bUpdate)
+ UpdateSplitterLayout();
+ }
+
+ int GetSplitterPos() const
+ {
+ return m_xySplitterPos;
+ }
+
+ bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE);
+ if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE))
+ return false;
+
+ if(nPane != SPLIT_PANE_NONE)
+ {
+ if(!::IsWindowVisible(m_hWndPane[nPane]))
+ ::ShowWindow(m_hWndPane[nPane], SW_SHOW);
+ int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
+ ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
+ if(m_nDefActivePane != nPane)
+ m_nDefActivePane = nPane;
+ }
+ else if(m_nSinglePane != SPLIT_PANE_NONE)
+ {
+ int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
+ ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
+ }
+
+ m_nSinglePane = nPane;
+ UpdateSplitterLayout();
+ return true;
+ }
+
+ int GetSinglePaneMode() const
+ {
+ return m_nSinglePane;
+ }
+
+ DWORD GetSplitterExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+ DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+#ifdef _DEBUG
+ if(IsProportional() && IsRightAligned())
+ ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
+#endif // _DEBUG
+ return dwPrevStyle;
+ }
+
+// Splitter operations
+ void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
+ {
+ m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
+ m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
+ ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
+ if(bUpdate)
+ UpdateSplitterLayout();
+ }
+
+ bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
+
+ if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
+ return false;
+ m_hWndPane[nPane] = hWnd;
+ ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
+ if(bUpdate)
+ UpdateSplitterLayout();
+ return true;
+ }
+
+ HWND GetSplitterPane(int nPane) const
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
+
+ if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
+ return false;
+ return m_hWndPane[nPane];
+ }
+
+ bool SetActivePane(int nPane)
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
+
+ if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
+ return false;
+ if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane)
+ return false;
+ ::SetFocus(m_hWndPane[nPane]);
+ m_nDefActivePane = nPane;
+ return true;
+ }
+
+ int GetActivePane() const
+ {
+ int nRet = SPLIT_PANE_NONE;
+ HWND hWndFocus = ::GetFocus();
+ if(hWndFocus != NULL)
+ {
+ for(int nPane = 0; nPane < m_nPanesCount; nPane++)
+ {
+ if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus))
+ {
+ nRet = nPane;
+ break;
+ }
+ }
+ }
+ return nRet;
+ }
+
+ bool ActivateNextPane(bool bNext = true)
+ {
+ int nPane = m_nSinglePane;
+ if(nPane == SPLIT_PANE_NONE)
+ {
+ switch(GetActivePane())
+ {
+ case SPLIT_PANE_LEFT:
+ nPane = SPLIT_PANE_RIGHT;
+ break;
+ case SPLIT_PANE_RIGHT:
+ nPane = SPLIT_PANE_LEFT;
+ break;
+ default:
+ nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
+ break;
+ }
+ }
+ return SetActivePane(nPane);
+ }
+
+ bool SetDefaultActivePane(int nPane)
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
+
+ if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
+ return false;
+ m_nDefActivePane = nPane;
+ return true;
+ }
+
+ bool SetDefaultActivePane(HWND hWnd)
+ {
+ for(int nPane = 0; nPane < m_nPanesCount; nPane++)
+ {
+ if(hWnd == m_hWndPane[nPane])
+ {
+ m_nDefActivePane = nPane;
+ return true;
+ }
+ }
+ return false; // not found
+ }
+
+ int GetDefaultActivePane() const
+ {
+ return m_nDefActivePane;
+ }
+
+ void DrawSplitter(CDCHandle dc)
+ {
+ ATLASSERT(dc.m_hDC != NULL);
+ if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
+ return;
+
+ T* pT = static_cast<T*>(this);
+ if(m_nSinglePane == SPLIT_PANE_NONE)
+ {
+ pT->DrawSplitterBar(dc);
+
+ for(int nPane = 0; nPane < m_nPanesCount; nPane++)
+ {
+ if(m_hWndPane[nPane] == NULL)
+ pT->DrawSplitterPane(dc, nPane);
+ }
+ }
+ else
+ {
+ if(m_hWndPane[m_nSinglePane] == NULL)
+ pT->DrawSplitterPane(dc, m_nSinglePane);
+ }
+ }
+
+// Overrideables
+ void DrawSplitterBar(CDCHandle dc)
+ {
+ RECT rect = { 0 };
+ if(GetSplitterBarRect(&rect))
+ {
+ dc.FillRect(&rect, COLOR_3DFACE);
+
+#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420))
+ if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0)
+ {
+ RECT rect2 = rect;
+ if(t_bVertical)
+ rect2.left = (rect.left + rect.right) / 2 - 1;
+ else
+ rect2.top = (rect.top + rect.bottom) / 2 - 1;
+
+ dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), t_bVertical);
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)
+
+ // draw 3D edge if needed
+ T* pT = static_cast<T*>(this);
+ if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
+ dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
+ }
+ }
+
+ // called only if pane is empty
+ void DrawSplitterPane(CDCHandle dc, int nPane)
+ {
+ RECT rect = { 0 };
+ if(GetSplitterPaneRect(nPane, &rect))
+ {
+ T* pT = static_cast<T*>(this);
+ if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
+ dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ dc.FillRect(&rect, COLOR_APPWORKSPACE);
+ }
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CSplitterImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+#endif // !_WIN32_WCE
+ if(IsInteractive())
+ {
+ MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
+ MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
+ MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
+ }
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+#ifndef _WIN32_WCE
+ MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
+#endif // !_WIN32_WCE
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->GetSystemSettings(false);
+
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ // try setting position if not set
+ if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
+ pT->SetSplitterPos();
+ // do painting
+ CPaintDC dc(pT->m_hWnd);
+ pT->DrawSplitter(dc.m_hDC);
+ return 0;
+ }
+
+ LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT)
+ {
+ DWORD dwPos = ::GetMessagePos();
+ POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
+ pT->ScreenToClient(&ptPos);
+ if(IsOverSplitterBar(ptPos.x, ptPos.y))
+ return 1;
+ }
+
+ bHandled = FALSE;
+ return 0;
+ }
+
+ LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ int xPos = GET_X_LPARAM(lParam);
+ int yPos = GET_Y_LPARAM(lParam);
+ if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd)
+ {
+ int xyNewSplitPos = 0;
+ if(t_bVertical)
+ xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
+ else
+ xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
+
+ if(xyNewSplitPos == -1) // avoid -1, that means middle
+ xyNewSplitPos = -2;
+
+ if(m_xySplitterPos != xyNewSplitPos)
+ {
+ if(m_bFullDrag)
+ {
+ if(pT->SetSplitterPos(xyNewSplitPos, true))
+ pT->UpdateWindow();
+ }
+ else
+ {
+ DrawGhostBar();
+ pT->SetSplitterPos(xyNewSplitPos, false);
+ DrawGhostBar();
+ }
+ }
+ }
+ else // not dragging, just set cursor
+ {
+ if(IsOverSplitterBar(xPos, yPos))
+ ::SetCursor(m_hCursor);
+ bHandled = FALSE;
+ }
+
+ return 0;
+ }
+
+ LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
+ {
+ int xPos = GET_X_LPARAM(lParam);
+ int yPos = GET_Y_LPARAM(lParam);
+ if(IsOverSplitterBar(xPos, yPos))
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetCapture();
+ ::SetCursor(m_hCursor);
+ if(!m_bFullDrag)
+ DrawGhostBar();
+ if(t_bVertical)
+ m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
+ else
+ m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ ::ReleaseCapture();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetSplitterPos(); // middle
+ return 0;
+ }
+
+ LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ if(!m_bFullDrag)
+ {
+ DrawGhostBar();
+ UpdateSplitterLayout();
+ T* pT = static_cast<T*>(this);
+ pT->UpdateWindow();
+ }
+ return 0;
+ }
+
+ LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
+ {
+ if(m_nSinglePane == SPLIT_PANE_NONE)
+ {
+ if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT)
+ ::SetFocus(m_hWndPane[m_nDefActivePane]);
+ }
+ else
+ {
+ ::SetFocus(m_hWndPane[m_nSinglePane]);
+ }
+ bHandled = FALSE;
+ return 1;
+ }
+
+#ifndef _WIN32_WCE
+ LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
+ if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT)
+ {
+ DWORD dwPos = ::GetMessagePos();
+ POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
+ pT->ScreenToClient(&pt);
+ RECT rcPane = { 0 };
+ for(int nPane = 0; nPane < m_nPanesCount; nPane++)
+ {
+ if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
+ {
+ m_nDefActivePane = nPane;
+ break;
+ }
+ }
+ }
+ return lRet;
+ }
+#endif // !_WIN32_WCE
+
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->GetSystemSettings(true);
+
+ return 0;
+ }
+
+// Implementation - internal helpers
+ void UpdateSplitterLayout()
+ {
+ if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
+ return;
+
+ T* pT = static_cast<T*>(this);
+ RECT rect = { 0 };
+ if(m_nSinglePane == SPLIT_PANE_NONE)
+ {
+ if(GetSplitterBarRect(&rect))
+ pT->InvalidateRect(&rect);
+
+ for(int nPane = 0; nPane < m_nPanesCount; nPane++)
+ {
+ if(GetSplitterPaneRect(nPane, &rect))
+ {
+ if(m_hWndPane[nPane] != NULL)
+ ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
+ else
+ pT->InvalidateRect(&rect);
+ }
+ }
+ }
+ else
+ {
+ if(GetSplitterPaneRect(m_nSinglePane, &rect))
+ {
+ if(m_hWndPane[m_nSinglePane] != NULL)
+ ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
+ else
+ pT->InvalidateRect(&rect);
+ }
+ }
+ }
+
+ bool GetSplitterBarRect(LPRECT lpRect) const
+ {
+ ATLASSERT(lpRect != NULL);
+ if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
+ return false;
+
+ if(t_bVertical)
+ {
+ lpRect->left = m_rcSplitter.left + m_xySplitterPos;
+ lpRect->top = m_rcSplitter.top;
+ lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
+ lpRect->bottom = m_rcSplitter.bottom;
+ }
+ else
+ {
+ lpRect->left = m_rcSplitter.left;
+ lpRect->top = m_rcSplitter.top + m_xySplitterPos;
+ lpRect->right = m_rcSplitter.right;
+ lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
+ }
+
+ return true;
+ }
+
+ bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
+ {
+ ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
+ ATLASSERT(lpRect != NULL);
+ bool bRet = true;
+ if(m_nSinglePane != SPLIT_PANE_NONE)
+ {
+ if(nPane == m_nSinglePane)
+ *lpRect = m_rcSplitter;
+ else
+ bRet = false;
+ }
+ else if(nPane == SPLIT_PANE_LEFT)
+ {
+ if(t_bVertical)
+ {
+ lpRect->left = m_rcSplitter.left;
+ lpRect->top = m_rcSplitter.top;
+ lpRect->right = m_rcSplitter.left + m_xySplitterPos;
+ lpRect->bottom = m_rcSplitter.bottom;
+ }
+ else
+ {
+ lpRect->left = m_rcSplitter.left;
+ lpRect->top = m_rcSplitter.top;
+ lpRect->right = m_rcSplitter.right;
+ lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
+ }
+ }
+ else if(nPane == SPLIT_PANE_RIGHT)
+ {
+ if(t_bVertical)
+ {
+ lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
+ lpRect->top = m_rcSplitter.top;
+ lpRect->right = m_rcSplitter.right;
+ lpRect->bottom = m_rcSplitter.bottom;
+ }
+ else
+ {
+ lpRect->left = m_rcSplitter.left;
+ lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
+ lpRect->right = m_rcSplitter.right;
+ lpRect->bottom = m_rcSplitter.bottom;
+ }
+ }
+ else
+ {
+ bRet = false;
+ }
+ return bRet;
+ }
+
+ bool IsOverSplitterRect(int x, int y) const
+ {
+ // -1 == don't check
+ return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
+ (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
+ }
+
+ bool IsOverSplitterBar(int x, int y) const
+ {
+ if(m_nSinglePane != SPLIT_PANE_NONE)
+ return false;
+ if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y))
+ return false;
+ int xy = t_bVertical ? x : y;
+ int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
+ return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
+ }
+
+ void DrawGhostBar()
+ {
+ RECT rect = { 0 };
+ if(GetSplitterBarRect(&rect))
+ {
+ // convert client to window coordinates
+ T* pT = static_cast<T*>(this);
+ RECT rcWnd = { 0 };
+ pT->GetWindowRect(&rcWnd);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2);
+ ::OffsetRect(&rect, -rcWnd.left, -rcWnd.top);
+
+ // invert the brush pattern (looks just like frame window sizing)
+ CWindowDC dc(pT->m_hWnd);
+ CBrush brush = CDCHandle::GetHalftoneBrush();
+ if(brush.m_hBrush != NULL)
+ {
+ CBrushHandle brushOld = dc.SelectBrush(brush);
+ dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
+ dc.SelectBrush(brushOld);
+ }
+ }
+ }
+
+ void GetSystemSettings(bool bUpdate)
+ {
+ if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0)
+ {
+#ifndef _WIN32_WCE
+ m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
+#else // CE specific
+ m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
+#endif // _WIN32_WCE
+ }
+
+ T* pT = static_cast<T*>(this);
+ if((pT->GetExStyle() & WS_EX_CLIENTEDGE))
+ {
+ m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
+ m_cxyMin = 0;
+ }
+ else
+ {
+ m_cxyBarEdge = 0;
+ m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
+ }
+
+#ifndef _WIN32_WCE
+ ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
+#endif // !_WIN32_WCE
+
+ if(bUpdate)
+ UpdateSplitterLayout();
+ }
+
+ bool IsProportional() const
+ {
+ return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
+ }
+
+ void StoreProportionalPos()
+ {
+ int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
+ if(cxyTotal > 0)
+ m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
+ else
+ m_nProportionalPos = 0;
+ ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos);
+ }
+
+ void UpdateProportionalPos()
+ {
+ int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
+ if(cxyTotal > 0)
+ {
+ int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
+ m_bUpdateProportionalPos = false;
+ T* pT = static_cast<T*>(this);
+ pT->SetSplitterPos(xyNewPos, false);
+ }
+ }
+
+ bool IsRightAligned() const
+ {
+ return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
+ }
+
+ void StoreRightAlignPos()
+ {
+ int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
+ if(cxyTotal > 0)
+ m_nProportionalPos = cxyTotal - m_xySplitterPos;
+ else
+ m_nProportionalPos = 0;
+ ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos);
+ }
+
+ void UpdateRightAlignPos()
+ {
+ int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
+ if(cxyTotal > 0)
+ {
+ m_bUpdateProportionalPos = false;
+ T* pT = static_cast<T*>(this);
+ pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
+ }
+ }
+
+ bool IsInteractive() const
+ {
+ return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
+ }
+};
+
+template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSplitterWindowImpl - Implements a splitter window
+
+template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical >
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
+
+ typedef CSplitterImpl< T , t_bVertical > _baseClass;
+
+ BEGIN_MSG_MAP(CSplitterWindowImpl)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ CHAIN_MSG_MAP(_baseClass)
+ FORWARD_NOTIFICATIONS()
+ END_MSG_MAP()
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ // handled, no background painting needed
+ return 1;
+ }
+
+ LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(wParam != SIZE_MINIMIZED)
+ SetSplitterRect();
+
+ bHandled = FALSE;
+ return 1;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSplitterWindow - Implements a splitter window to be used as is
+
+template <bool t_bVertical = true>
+class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical>, t_bVertical>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
+};
+
+typedef CSplitterWindowT<true> CSplitterWindow;
+typedef CSplitterWindowT<false> CHorSplitterWindow;
+
+}; // namespace WTL
+
+#endif // __ATLSPLIT_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLTHEME_H__
+#define __ATLTHEME_H__
+
+#pragma once
+
+#ifdef _WIN32_WCE
+ #error atltheme.h is not supported on Windows CE
+#endif
+
+#ifndef __ATLAPP_H__
+ #error atltheme.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atltheme.h requires atlwin.h to be included first
+#endif
+
+#if (_WIN32_WINNT < 0x0501)
+ #error atltheme.h requires _WIN32_WINNT >= 0x0501
+#endif // (_WIN32_WINNT < 0x0501)
+
+#if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN))
+ #include <vssym32.h>
+#else
+ #ifndef TMSCHEMA_H
+ #include <tmschema.h>
+ #endif
+#endif
+
+#ifndef _UXTHEME_H_
+#include <uxtheme.h>
+#endif
+#pragma comment(lib, "uxtheme.lib")
+
+// Note: To create an application that also runs on older versions of Windows,
+// use delay load of uxtheme.dll and ensure that no calls to the Theme API are
+// made if theming is not supported. It is enough to check if m_hTheme is NULL.
+// Example:
+// if(m_hTheme != NULL)
+// {
+// DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL);
+// DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect);
+// }
+// else
+// {
+// dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH);
+// dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+// }
+//
+// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib,
+// and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the
+// project properties.
+#if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)
+ #pragma comment(lib, "delayimp.lib")
+ #pragma comment(linker, "/delayload:uxtheme.dll")
+#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)
+
+// Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h
+// is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE
+#ifndef _WTL_NEW_UXTHEME
+ #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)
+ #define _WTL_NEW_UXTHEME
+ #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)
+#endif // _WTL_NEW_UXTHEME
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CTheme
+// CThemeImpl<T, TBase>
+//
+// CBufferedPaint
+// CBufferedPaintImpl<T>
+// CBufferedPaintWindowImpl<T, TBase, TWinTraits>
+// CBufferedAnimation
+// CBufferedAnimationImpl<T, TState>
+// CBufferedAnimationWindowImpl<T, TState, TBase, TWinTraits>
+//
+// Global functions:
+// AtlDrawThemeClientEdge()
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CTheme - wrapper for theme handle
+
+class CTheme
+{
+public:
+// Data members
+ HTHEME m_hTheme;
+ static int m_nIsThemingSupported;
+
+// Constructor
+ CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme)
+ {
+ IsThemingSupported();
+ }
+
+// Operators and helpers
+ bool IsThemeNull() const
+ {
+ return (m_hTheme == NULL);
+ }
+
+ CTheme& operator =(HTHEME hTheme)
+ {
+ m_hTheme = hTheme;
+ return *this;
+ }
+
+ operator HTHEME() const
+ {
+ return m_hTheme;
+ }
+
+ void Attach(HTHEME hTheme)
+ {
+ m_hTheme = hTheme;
+ }
+
+ HTHEME Detach()
+ {
+ HTHEME hTheme = m_hTheme;
+ m_hTheme = NULL;
+ return hTheme;
+ }
+
+// Theme support helper
+ static bool IsThemingSupported()
+ {
+ if(m_nIsThemingSupported == -1)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n"));
+ ATLASSERT(FALSE);
+ return false;
+ }
+
+ if(m_nIsThemingSupported == -1)
+ {
+ HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
+ m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0;
+ if(hThemeDLL != NULL)
+ ::FreeLibrary(hThemeDLL);
+ }
+
+ lock.Unlock();
+ }
+
+ ATLASSERT(m_nIsThemingSupported != -1);
+ return (m_nIsThemingSupported == 1);
+ }
+
+// Operations and theme properties
+ HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList)
+ {
+ if(!IsThemingSupported())
+ return NULL;
+
+ ATLASSERT(m_hTheme == NULL);
+ m_hTheme = ::OpenThemeData(hWnd, pszClassList);
+ return m_hTheme;
+ }
+
+ HRESULT CloseThemeData()
+ {
+ HRESULT hRet = S_FALSE;
+ if(m_hTheme != NULL)
+ {
+ hRet = ::CloseThemeData(m_hTheme);
+ if(SUCCEEDED(hRet))
+ m_hTheme = NULL;
+ }
+ return hRet;
+ }
+
+ HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect);
+ }
+
+ HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions);
+ }
+
+ HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect);
+ }
+
+ HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect);
+ }
+
+ HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect);
+ }
+
+ HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize);
+ }
+
+ HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect);
+ }
+
+ HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+#ifdef _WTL_NEW_UXTHEME
+ return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric);
+#else // !_WTL_NEW_UXTHEME
+ // Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW
+ return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric);
+#endif // !_WTL_NEW_UXTHEME
+ }
+
+ HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion);
+ }
+
+ HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode);
+ }
+
+ HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect);
+ }
+
+ HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex);
+ }
+
+ BOOL IsThemePartDefined(int nPartID, int nStateID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::IsThemePartDefined(m_hTheme, nPartID, nStateID);
+ }
+
+ BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID);
+ }
+
+ HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor);
+ }
+
+ HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal);
+ }
+
+ HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars);
+ }
+
+ HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal);
+ }
+
+ HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal);
+ }
+
+ HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal);
+ }
+
+ HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint);
+ }
+
+ // deprecated
+ HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+#ifdef _WTL_NEW_UXTHEME
+ return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
+#else // !_WTL_NEW_UXTHEME
+ // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
+ return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);
+#endif // !_WTL_NEW_UXTHEME
+ }
+
+ HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+#ifdef _WTL_NEW_UXTHEME
+ return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
+#else // !_WTL_NEW_UXTHEME
+ // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
+ return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);
+#endif // !_WTL_NEW_UXTHEME
+ }
+
+ HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect);
+ }
+
+ HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins);
+ }
+
+ HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList);
+ }
+
+ HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin);
+ }
+
+ HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars);
+ }
+
+ COLORREF GetThemeSysColor(int nColorID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysColor(m_hTheme, nColorID);
+ }
+
+ HBRUSH GetThemeSysColorBrush(int nColorID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysColorBrush(m_hTheme, nColorID);
+ }
+
+ int GetThemeSysSize(int nSizeID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysSize(m_hTheme, nSizeID);
+ }
+
+ BOOL GetThemeSysBool(int nBoolID) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysBool(m_hTheme, nBoolID);
+ }
+
+ HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+#ifdef _WTL_NEW_UXTHEME
+ return ::GetThemeSysFont(m_hTheme, nFontID, plf);
+#else // !_WTL_NEW_UXTHEME
+ // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
+ return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf);
+#endif // !_WTL_NEW_UXTHEME
+ }
+
+ HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars);
+ }
+
+ HRESULT GetThemeSysInt(int nIntID, int* pnValue) const
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeSysInt(m_hTheme, nIntID, pnValue);
+ }
+
+#ifdef _WTL_NEW_UXTHEME
+ HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags)
+ {
+ if(!IsThemingSupported())
+ return NULL;
+
+ ATLASSERT(m_hTheme == NULL);
+ m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags);
+ return m_hTheme;
+ }
+
+ HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions);
+ }
+
+ HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration);
+ }
+#endif // _WTL_NEW_UXTHEME
+
+#if (_WIN32_WINNT >= 0x0600)
+ HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap);
+ }
+
+ HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance)
+ {
+ ATLASSERT(m_hTheme != NULL);
+ return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+};
+
+__declspec(selectany) int CTheme::m_nIsThemingSupported = -1;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CThemeImpl - theme support implementation
+
+// Derive from this class to implement window with theme support.
+// Example:
+// class CMyThemeWindow : public CWindowImpl<CMyThemeWindow>, public CThemeImpl<CMyThemeWindow>
+// {
+// ...
+// BEGIN_MSG_MAP(CMyThemeWindow)
+// CHAIN_MSG_MAP(CThemeImpl<CMyThemeWindow>)
+// ...
+// END_MSG_MAP()
+// ...
+// };
+//
+// If you set theme class list, the class will automaticaly open/close/reopen theme data.
+
+
+// Helper for drawing theme client edge
+inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0)
+{
+ ATLASSERT(hTheme != NULL);
+ ATLASSERT(::IsWindow(hWnd));
+
+ CWindowDC dc(hWnd);
+ if(dc.IsNull())
+ return false;
+
+ // Get border size
+ int cxBorder = GetSystemMetrics(SM_CXBORDER);
+ int cyBorder = GetSystemMetrics(SM_CYBORDER);
+ if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder)))
+ cyBorder = cxBorder;
+
+ RECT rect;
+ ::GetWindowRect(hWnd, &rect);
+
+ // Remove the client edge from the update region
+ int cxEdge = GetSystemMetrics(SM_CXEDGE);
+ int cyEdge = GetSystemMetrics(SM_CYEDGE);
+ ::InflateRect(&rect, -cxEdge, -cyEdge);
+ CRgn rgn;
+ rgn.CreateRectRgnIndirect(&rect);
+ if(rgn.IsNull())
+ return false;
+
+ if(hRgnUpdate != NULL)
+ rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND);
+
+ ::OffsetRect(&rect, -rect.left, -rect.top);
+
+ ::OffsetRect(&rect, cxEdge, cyEdge);
+ dc.ExcludeClipRect(&rect);
+ ::InflateRect(&rect, cxEdge, cyEdge);
+
+ ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL);
+
+ // Use background brush too, since theme border might not cover everything
+ if(cxBorder < cxEdge && cyBorder < cyEdge)
+ {
+ if(hBrush == NULL)
+// need conditional code because types don't match in winuser.h
+#ifdef _WIN64
+ hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND);
+#else
+ hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND));
+#endif
+
+ ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge);
+ dc.FillRect(&rect, hBrush);
+ }
+
+ ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L);
+
+ return true;
+}
+
+
+// Theme extended styles
+#define THEME_EX_3DCLIENTEDGE 0x00000001
+#define THEME_EX_THEMECLIENTEDGE 0x00000002
+
+template <class T, class TBase = CTheme>
+class CThemeImpl : public TBase
+{
+public:
+// Data members
+ LPWSTR m_lpstrThemeClassList;
+ DWORD m_dwExtendedStyle; // theme specific extended styles
+
+// Constructor & destructor
+ CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0)
+ { }
+
+ ~CThemeImpl()
+ {
+ delete [] m_lpstrThemeClassList;
+ }
+
+// Attributes
+ bool SetThemeClassList(LPCWSTR lpstrThemeClassList)
+ {
+ if(m_lpstrThemeClassList != NULL)
+ {
+ delete [] m_lpstrThemeClassList;
+ m_lpstrThemeClassList = NULL;
+ }
+
+ if(lpstrThemeClassList == NULL)
+ return true;
+
+ int cchLen = lstrlenW(lpstrThemeClassList) + 1;
+ ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]);
+ if(m_lpstrThemeClassList == NULL)
+ return false;
+
+ SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList);
+
+ return true;
+ }
+
+ bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const
+ {
+ int cchLen = lstrlenW(m_lpstrThemeClassList) + 1;
+ if(cchListBuffer < cchLen)
+ return false;
+
+ SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList);
+
+ return true;
+ }
+
+ LPCWSTR GetThemeClassList() const
+ {
+ return m_lpstrThemeClassList;
+ }
+
+ DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
+ {
+ DWORD dwPrevStyle = m_dwExtendedStyle;
+ if(dwMask == 0)
+ m_dwExtendedStyle = dwExtendedStyle;
+ else
+ m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
+ return dwPrevStyle;
+ }
+
+ DWORD GetThemeExtendedStyle() const
+ {
+ return m_dwExtendedStyle;
+ }
+
+// Operations
+ HTHEME OpenThemeData()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ ATLASSERT(m_lpstrThemeClassList != NULL);
+ if(m_lpstrThemeClassList == NULL)
+ return NULL;
+ CloseThemeData();
+ return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList);
+ }
+
+ HTHEME OpenThemeData(LPCWSTR pszClassList)
+ {
+ if(!SetThemeClassList(pszClassList))
+ return NULL;
+ return OpenThemeData();
+ }
+
+ HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList);
+ }
+
+ HTHEME GetWindowTheme() const
+ {
+ if(!IsThemingSupported())
+ return NULL;
+
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::GetWindowTheme(pT->m_hWnd);
+ }
+
+ HRESULT EnableThemeDialogTexture(DWORD dwFlags)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags);
+ }
+
+ BOOL IsThemeDialogTextureEnabled() const
+ {
+ if(!IsThemingSupported())
+ return FALSE;
+
+ const T* pT = static_cast<const T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::IsThemeDialogTextureEnabled(pT->m_hWnd);
+ }
+
+ HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+#ifdef _WTL_NEW_UXTHEME
+ return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect);
+#else
+ return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect);
+#endif
+ }
+
+#ifdef _WTL_NEW_UXTHEME
+ HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute);
+ }
+
+ HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ WTA_OPTIONS opt = { dwAttributes, dwMask };
+ return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt));
+ }
+
+ HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL)
+ {
+ if(!IsThemingSupported())
+ return S_FALSE;
+
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect);
+ }
+#endif // _WTL_NEW_UXTHEME
+
+// Message map and handlers
+ // Note: If you handle any of these messages in your derived class,
+ // it is better to put CHAIN_MSG_MAP at the start of your message map.
+ BEGIN_MSG_MAP(CThemeImpl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
+ MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
+ END_MSG_MAP()
+
+ LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if(m_lpstrThemeClassList != NULL)
+ OpenThemeData();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ CloseThemeData();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ CloseThemeData();
+ if(m_lpstrThemeClassList != NULL)
+ OpenThemeData();
+ bHandled = FALSE;
+ return 1;
+ }
+
+ LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ LRESULT lRet = 0;
+ bHandled = FALSE;
+ if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0))
+ {
+ if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0)
+ {
+ lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam);
+ bHandled = TRUE;
+ }
+ else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0))
+ {
+ HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL;
+ if(pT->DrawThemeClientEdge(hRgn))
+ bHandled = TRUE;
+ }
+ }
+ return lRet;
+ }
+
+// Drawing helper
+ bool DrawThemeClientEdge(HRGN hRgnUpdate)
+ {
+ T* pT = static_cast<T*>(this);
+ return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Buffered Paint and Animation
+
+#ifdef _WTL_NEW_UXTHEME
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedPaintBase - Buffered Paint support for othe classes
+
+class CBufferedPaintBase
+{
+public:
+ static int m_nIsBufferedPaintSupported;
+
+ CBufferedPaintBase()
+ {
+ if(IsBufferedPaintSupported())
+ ATLVERIFY(SUCCEEDED(::BufferedPaintInit()));
+ }
+
+ ~CBufferedPaintBase()
+ {
+ if(IsBufferedPaintSupported())
+ ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit()));
+ }
+
+ static bool IsBufferedPaintSupported()
+ {
+ if(m_nIsBufferedPaintSupported == -1)
+ {
+ CStaticDataInitCriticalSectionLock lock;
+ if(FAILED(lock.Lock()))
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n"));
+ ATLASSERT(FALSE);
+ return false;
+ }
+
+ if(m_nIsBufferedPaintSupported == -1)
+ m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0;
+
+ lock.Unlock();
+ }
+
+ ATLASSERT(m_nIsBufferedPaintSupported != -1);
+ return (m_nIsBufferedPaintSupported == 1);
+ }
+};
+
+__declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedPaint - support for buffered paint functions
+
+class CBufferedPaint
+{
+public:
+ HPAINTBUFFER m_hPaintBuffer;
+
+ CBufferedPaint() : m_hPaintBuffer(NULL)
+ { }
+
+ ~CBufferedPaint()
+ {
+ ATLVERIFY(SUCCEEDED(End()));
+ }
+
+ bool IsNull() const
+ {
+ return (m_hPaintBuffer == NULL);
+ }
+
+ HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint)
+ {
+ ATLASSERT(m_hPaintBuffer == NULL);
+ m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint);
+ return m_hPaintBuffer;
+ }
+
+ HRESULT End(BOOL bUpdate = TRUE)
+ {
+ HRESULT hRet = S_FALSE;
+ if(m_hPaintBuffer != NULL)
+ {
+ hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate);
+ m_hPaintBuffer = NULL;
+ }
+ return hRet;
+ }
+
+ HRESULT GetTargetRect(LPRECT pRect) const
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect);
+ }
+
+ HDC GetTargetDC() const
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::GetBufferedPaintTargetDC(m_hPaintBuffer);
+ }
+
+ HDC GetPaintDC() const
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::GetBufferedPaintDC(m_hPaintBuffer);
+ }
+
+ HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow);
+ }
+
+ HRESULT Clear(const RECT* pRect = NULL)
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::BufferedPaintClear(m_hPaintBuffer, pRect);
+ }
+
+ HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL)
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha);
+ }
+
+ HRESULT MakeOpaque(const RECT* pRect = NULL)
+ {
+ ATLASSERT(m_hPaintBuffer != NULL);
+ return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedPaintImpl - provides buffered paint for any window
+
+template <class T>
+class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase
+{
+public:
+ CBufferedPaint m_BufferedPaint;
+ BP_BUFFERFORMAT m_dwFormat;
+ BP_PAINTPARAMS m_PaintParams;
+
+ CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB)
+ {
+ memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
+ m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CBufferedPaintImpl)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ END_MSG_MAP()
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background needed
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ if(wParam != NULL)
+ {
+ RECT rect = { 0 };
+ pT->GetClientRect(&rect);
+ pT->DoPaint((HDC)wParam, rect);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint);
+ }
+
+ return 0;
+ }
+
+// Overrideables
+ void DoBufferedPaint(CDCHandle dc, RECT& rect)
+ {
+ HDC hDCPaint = NULL;
+ if(IsBufferedPaintSupported())
+ m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint);
+
+ T* pT = static_cast<T*>(this);
+ if(hDCPaint != NULL)
+ pT->DoPaint(hDCPaint, rect);
+ else
+ pT->DoPaint(dc.m_hDC, rect);
+
+ if(IsBufferedPaintSupported())
+ m_BufferedPaint.End();
+ }
+
+ void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/)
+ {
+ // must be implemented in a derived class
+ ATLASSERT(FALSE);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedPaintWindowImpl - implements a window that uses buffered paint
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CBufferedPaintWindowImpl :
+ public ATL::CWindowImpl<T, TBase, TWinTraits>,
+ public CBufferedPaintImpl< T >
+{
+public:
+ BEGIN_MSG_MAP(CBufferedPaintWindowImpl)
+ CHAIN_MSG_MAP(CBufferedPaintImpl< T >)
+ END_MSG_MAP()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedAnimation - support for buffered animation
+
+class CBufferedAnimation
+{
+public:
+ HANIMATIONBUFFER m_hAnimationBuffer;
+
+ CBufferedAnimation() : m_hAnimationBuffer(NULL)
+ { }
+
+ ~CBufferedAnimation()
+ {
+ ATLVERIFY(SUCCEEDED(End()));
+ }
+
+ bool IsNull() const
+ {
+ return (m_hAnimationBuffer == NULL);
+ }
+
+ HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo)
+ {
+ ATLASSERT(m_hAnimationBuffer == NULL);
+ m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo);
+ return m_hAnimationBuffer;
+ }
+
+ HRESULT End(BOOL bUpdate = TRUE)
+ {
+ HRESULT hRet = S_FALSE;
+ if(m_hAnimationBuffer != NULL)
+ {
+ hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate);
+ m_hAnimationBuffer = NULL;
+ }
+ return hRet;
+ }
+
+ static bool IsRendering(HWND hWnd, HDC hDC)
+ {
+ return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedAnimationImpl - provides buffered animation support for any window
+
+// Note: You can either use m_State and m_NewState to store the state information
+// for the animation change, or map your state to those data members. DoPaint()
+// should only rely on the state information that is passed to it.
+
+template <class T, class TState = DWORD_PTR>
+class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase
+{
+public:
+ BP_BUFFERFORMAT m_dwFormat;
+ BP_PAINTPARAMS m_PaintParams;
+ BP_ANIMATIONPARAMS m_AnimationParams;
+
+ TState m_State;
+ TState m_NewState;
+
+ CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB)
+ {
+ memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
+ m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
+
+ memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS));
+ m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS);
+ m_AnimationParams.style = BPAS_LINEAR;
+ m_AnimationParams.dwDuration = 500;
+
+ T* pT = static_cast<T*>(this);
+ pT->SetState(InitialState);
+ pT->SetNewState(InitialState);
+ }
+
+ DWORD GetDuration() const
+ {
+ return m_AnimationParams.dwDuration;
+ }
+
+ void SetDuration(DWORD dwDuration)
+ {
+ m_AnimationParams.dwDuration = dwDuration;
+ }
+
+ void DoAnimation(TState NewState, const RECT* pRect = NULL)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->SetNewState(NewState);
+
+ pT->InvalidateRect(pRect, FALSE);
+ pT->UpdateWindow();
+
+ pT->SetState(NewState);
+ }
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CBufferedAnimationImpl)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+ MESSAGE_HANDLER(WM_PAINT, OnPaint)
+ MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+ END_MSG_MAP()
+
+ LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ return 1; // no background needed
+ }
+
+ LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ if(wParam != NULL)
+ {
+ RECT rect = { 0 };
+ pT->GetClientRect(&rect);
+ pT->DoPaint((HDC)wParam, rect, m_NewState);
+ }
+ else
+ {
+ CPaintDC dc(pT->m_hWnd);
+ pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint);
+ }
+
+ return 0;
+ }
+
+// Overrideables
+ void SetState(TState State)
+ {
+ m_State = State;
+ }
+
+ void SetNewState(TState State)
+ {
+ m_NewState = State;
+ }
+
+ bool AreStatesEqual() const
+ {
+ return (m_State == m_NewState);
+ }
+
+ void DoAnimationPaint(CDCHandle dc, RECT& rect)
+ {
+ T* pT = static_cast<T*>(this);
+ if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc))
+ return;
+
+ DWORD dwDurationSave = m_AnimationParams.dwDuration;
+ if(pT->AreStatesEqual())
+ m_AnimationParams.dwDuration = 0;
+
+ HDC hdcFrom = NULL, hdcTo = NULL;
+ CBufferedAnimation ba;
+ if(IsBufferedPaintSupported())
+ ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo);
+
+ if(!ba.IsNull())
+ {
+ if(hdcFrom != NULL)
+ pT->DoPaint(hdcFrom, rect, m_State);
+
+ if (hdcTo != NULL)
+ pT->DoPaint(hdcTo, rect, m_NewState);
+ }
+ else
+ {
+ pT->DoPaint(dc.m_hDC, rect, m_NewState);
+ }
+
+ m_AnimationParams.dwDuration = dwDurationSave;
+ }
+
+ void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/)
+ {
+ // must be implemented in a derived class
+ ATLASSERT(FALSE);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CBufferedAnimationWindowImpl - implements a window that uses buffered animation
+
+template <class T, class TState = DWORD_PTR, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CBufferedAnimationWindowImpl :
+ public ATL::CWindowImpl<T, TBase, TWinTraits>,
+ public CBufferedAnimationImpl< T, TState >
+{
+public:
+ CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState)
+ { }
+
+ typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation;
+ BEGIN_MSG_MAP(CBufferedAnimationWindowImpl)
+ CHAIN_MSG_MAP(_baseBufferedAnimation)
+ END_MSG_MAP()
+};
+
+#endif // _WTL_NEW_UXTHEME
+
+}; // namespace WTL
+
+#endif // __ATLTHEME_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLUSER_H__
+#define __ATLUSER_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atluser.h requires atlapp.h to be included first
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CMenuItemInfo
+// CMenuT<t_bManaged>
+// CAcceleratorT<t_bManaged>
+// CIconT<t_bManaged>
+// CCursorT<t_bManaged>
+// CResource
+//
+// Global functions:
+// AtlMessageBox()
+//
+// AtlLoadAccelerators()
+// AtlLoadMenu()
+// AtlLoadBitmap()
+// AtlLoadSysBitmap()
+// AtlLoadCursor()
+// AtlLoadSysCursor()
+// AtlLoadIcon()
+// AtlLoadSysIcon()
+// AtlLoadBitmapImage()
+// AtlLoadCursorImage()
+// AtlLoadIconImage()
+// AtlLoadSysBitmapImage()
+// AtlLoadSysCursorImage()
+// AtlLoadSysIconImage()
+// AtlLoadString()
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// AtlMessageBox - accepts both memory and resource based strings
+
+inline int AtlMessageBox(HWND hWndOwner, ATL::_U_STRINGorID message, ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uType = MB_OK | MB_ICONINFORMATION)
+{
+ ATLASSERT(hWndOwner == NULL || ::IsWindow(hWndOwner));
+
+ LPTSTR lpstrMessage = NULL;
+ if(IS_INTRESOURCE(message.m_lpstr))
+ {
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrMessage = new TCHAR[nLen]);
+ if(lpstrMessage == NULL)
+ {
+ ATLASSERT(FALSE);
+ return 0;
+ }
+ int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(message.m_lpstr), lpstrMessage, nLen);
+ if(nRes < nLen - 1)
+ break;
+ delete [] lpstrMessage;
+ lpstrMessage = NULL;
+ }
+
+ message.m_lpstr = lpstrMessage;
+ }
+
+ LPTSTR lpstrTitle = NULL;
+ if(IS_INTRESOURCE(title.m_lpstr) && LOWORD(title.m_lpstr) != 0)
+ {
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrTitle = new TCHAR[nLen]);
+ if(lpstrTitle == NULL)
+ {
+ ATLASSERT(FALSE);
+ return 0;
+ }
+ int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(title.m_lpstr), lpstrTitle, nLen);
+ if(nRes < nLen - 1)
+ break;
+ delete [] lpstrTitle;
+ lpstrTitle = NULL;
+ }
+
+ title.m_lpstr = lpstrTitle;
+ }
+
+ int nRet = ::MessageBox(hWndOwner, message.m_lpstr, title.m_lpstr, uType);
+
+ delete [] lpstrMessage;
+ delete [] lpstrTitle;
+
+ return nRet;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CMenu
+
+#if (WINVER >= 0x0500)
+ #ifndef MII_SIZEOF_STRUCT
+ #define MII_SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
+ #endif
+ #define MENUITEMINFO_SIZE_VERSION_400A MII_SIZEOF_STRUCT(MENUITEMINFOA, cch)
+ #define MENUITEMINFO_SIZE_VERSION_400W MII_SIZEOF_STRUCT(MENUITEMINFOW, cch)
+ #ifdef UNICODE
+ #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400W
+ #else
+ #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400A
+ #endif // !UNICODE
+#endif // (WINVER >= 0x0500)
+
+class CMenuItemInfo : public MENUITEMINFO
+{
+public:
+ CMenuItemInfo()
+ {
+ memset(this, 0, sizeof(MENUITEMINFO));
+ cbSize = sizeof(MENUITEMINFO);
+#if (WINVER >= 0x0500)
+ // adjust struct size if running on older version of Windows
+ if(AtlIsOldWindows())
+ {
+ ATLASSERT(cbSize > MENUITEMINFO_SIZE_VERSION_400); // must be
+ cbSize = MENUITEMINFO_SIZE_VERSION_400;
+ }
+#endif // (WINVER >= 0x0500)
+ }
+};
+
+
+// forward declarations
+template <bool t_bManaged> class CMenuT;
+typedef CMenuT<false> CMenuHandle;
+typedef CMenuT<true> CMenu;
+
+
+template <bool t_bManaged>
+class CMenuT
+{
+public:
+// Data members
+ HMENU m_hMenu;
+
+// Constructor/destructor/operators
+ CMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu)
+ { }
+
+ ~CMenuT()
+ {
+ if(t_bManaged && m_hMenu != NULL)
+ DestroyMenu();
+ }
+
+ CMenuT<t_bManaged>& operator =(HMENU hMenu)
+ {
+ Attach(hMenu);
+ return *this;
+ }
+
+ void Attach(HMENU hMenuNew)
+ {
+ ATLASSERT(::IsMenu(hMenuNew));
+ if(t_bManaged && m_hMenu != NULL && m_hMenu != hMenuNew)
+ ::DestroyMenu(m_hMenu);
+ m_hMenu = hMenuNew;
+ }
+
+ HMENU Detach()
+ {
+ HMENU hMenu = m_hMenu;
+ m_hMenu = NULL;
+ return hMenu;
+ }
+
+ operator HMENU() const { return m_hMenu; }
+
+ bool IsNull() const { return (m_hMenu == NULL); }
+
+ BOOL IsMenu() const
+ {
+ return ::IsMenu(m_hMenu);
+ }
+
+// Create/destroy methods
+ BOOL CreateMenu()
+ {
+ ATLASSERT(m_hMenu == NULL);
+ m_hMenu = ::CreateMenu();
+ return (m_hMenu != NULL) ? TRUE : FALSE;
+ }
+
+ BOOL CreatePopupMenu()
+ {
+ ATLASSERT(m_hMenu == NULL);
+ m_hMenu = ::CreatePopupMenu();
+ return (m_hMenu != NULL) ? TRUE : FALSE;
+ }
+
+ BOOL LoadMenu(ATL::_U_STRINGorID menu)
+ {
+ ATLASSERT(m_hMenu == NULL);
+ m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);
+ return (m_hMenu != NULL) ? TRUE : FALSE;
+ }
+
+#ifndef _WIN32_WCE
+ BOOL LoadMenuIndirect(const void* lpMenuTemplate)
+ {
+ ATLASSERT(m_hMenu == NULL);
+ m_hMenu = ::LoadMenuIndirect(lpMenuTemplate);
+ return (m_hMenu != NULL) ? TRUE : FALSE;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DestroyMenu()
+ {
+ if (m_hMenu == NULL)
+ return FALSE;
+ BOOL bRet = ::DestroyMenu(m_hMenu);
+ if(bRet)
+ m_hMenu = NULL;
+ return bRet;
+ }
+
+// Menu Operations
+ BOOL DeleteMenu(UINT nPosition, UINT nFlags)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::DeleteMenu(m_hMenu, nPosition, nFlags);
+ }
+
+ BOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = NULL)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+#ifndef _WIN32_WCE
+#if (WINVER >= 0x0500)
+ x = _FixTrackMenuPopupX(x, y);
+#endif // !(WINVER >= 0x0500)
+ return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect);
+#else // CE specific
+ lpRect;
+ return ::TrackPopupMenuEx(m_hMenu, nFlags, x, y, hWnd, NULL);
+#endif // _WIN32_WCE
+ }
+
+ BOOL TrackPopupMenuEx(UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm = NULL)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ x = _FixTrackMenuPopupX(x, y);
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ return ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm);
+ }
+
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ // helper that fixes popup menu X position when it's off-screen
+ static int _FixTrackMenuPopupX(int x, int y)
+ {
+ POINT pt = { x, y };
+ HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
+ if(hMonitor == NULL)
+ {
+ HMONITOR hMonitorNear = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
+ if(hMonitorNear != NULL)
+ {
+ MONITORINFO mi = { 0 };
+ mi.cbSize = sizeof(MONITORINFO);
+ if(::GetMonitorInfo(hMonitorNear, &mi) != FALSE)
+ {
+ if(x < mi.rcWork.left)
+ x = mi.rcWork.left;
+ else if(x > mi.rcWork.right)
+ x = mi.rcWork.right;
+ }
+ }
+ }
+
+ return x;
+ }
+
+ BOOL GetMenuInfo(LPMENUINFO lpMenuInfo) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuInfo(m_hMenu, lpMenuInfo);
+ }
+
+ BOOL SetMenuInfo(LPCMENUINFO lpMenuInfo)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::SetMenuInfo(m_hMenu, lpMenuInfo);
+ }
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+
+// Menu Item Operations
+ BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem);
+ }
+
+ BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::AppendMenu(m_hMenu, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::AppendMenu(m_hMenu, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);
+ }
+
+ BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::AppendMenu(m_hMenu, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);
+ }
+#endif // !_WIN32_WCE
+
+ UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return (UINT)::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck);
+ }
+
+ UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL HiliteMenuItem(HWND hWnd, UINT uIDHiliteItem, UINT uHilite)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::HiliteMenuItem(hWnd, m_hMenu, uIDHiliteItem, uHilite);
+ }
+
+ int GetMenuItemCount() const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuItemCount(m_hMenu);
+ }
+
+ UINT GetMenuItemID(int nPos) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuItemID(m_hMenu, nPos);
+ }
+
+ UINT GetMenuState(UINT nID, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuState(m_hMenu, nID, nFlags);
+ }
+
+ int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags);
+ }
+
+ int GetMenuStringLen(UINT nIDItem, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags);
+ }
+
+#ifndef _ATL_NO_COM
+ BOOL GetMenuString(UINT nIDItem, BSTR& bstrText, UINT nFlags) const
+ {
+ USES_CONVERSION;
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(bstrText == NULL);
+
+ int nLen = GetMenuStringLen(nIDItem, nFlags);
+ if(nLen == 0)
+ {
+ bstrText = ::SysAllocString(OLESTR(""));
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+
+ nLen++; // increment to include terminating NULL char
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ LPTSTR lpszText = buff.Allocate(nLen);
+ if(lpszText == NULL)
+ return FALSE;
+
+ if(!GetMenuString(nIDItem, lpszText, nLen, nFlags))
+ return FALSE;
+
+ bstrText = ::SysAllocString(T2OLE(lpszText));
+ return (bstrText != NULL) ? TRUE : FALSE;
+ }
+#endif // !_ATL_NO_COM
+
+#elif (_ATL_VER >= 0x0800)
+ int GetMenuItemCount() const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ATL::GetMenuItemCount(m_hMenu);
+ }
+
+ UINT GetMenuItemID(int nPos) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ATL::GetMenuItemID(m_hMenu, nPos);
+ }
+
+ UINT GetMenuState(UINT nID, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ATL::GetMenuState(m_hMenu, nID, nFlags);
+ }
+
+ int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ATL::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags);
+ }
+
+ int GetMenuStringLen(UINT nIDItem, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ATL::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags);
+ }
+#endif // (_ATL_VER >= 0x0800)
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ int GetMenuString(UINT nIDItem, _CSTRING_NS::CString& strText, UINT nFlags) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+
+ int nLen = GetMenuStringLen(nIDItem, nFlags);
+ if(nLen == 0)
+ return 0;
+
+ nLen++; // increment to include terminating NULL char
+ LPTSTR lpstr = strText.GetBufferSetLength(nLen);
+ if(lpstr == NULL)
+ return 0;
+ int nRet = GetMenuString(nIDItem, lpstr, nLen, nFlags);
+ strText.ReleaseBuffer();
+ return nRet;
+ }
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ CMenuHandle GetSubMenu(int nPos) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return CMenuHandle(::GetSubMenu(m_hMenu, nPos));
+ }
+
+ BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);
+ }
+
+ BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);
+ }
+
+ BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::InsertMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);
+ }
+
+ BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);
+ }
+
+ BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);
+ }
+
+ BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);
+ }
+
+ BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ ATLASSERT(::IsMenu(hSubMenu));
+ return ::ModifyMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL RemoveMenu(UINT nPosition, UINT nFlags)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::RemoveMenu(m_hMenu, nPosition, nFlags);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, HBITMAP hBmpUnchecked, HBITMAP hBmpChecked)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::SetMenuItemBitmaps(m_hMenu, nPosition, nFlags, hBmpUnchecked, hBmpChecked);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags);
+ }
+
+ BOOL GetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return (BOOL)::GetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii);
+ }
+
+ BOOL SetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return (BOOL)::SetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL InsertMenuItem(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return (BOOL)::InsertMenuItem(m_hMenu, uItem, bByPosition, lpmii);
+ }
+
+ UINT GetMenuDefaultItem(BOOL bByPosition = FALSE, UINT uFlags = 0U) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuDefaultItem(m_hMenu, (UINT)bByPosition, uFlags);
+ }
+
+ BOOL SetMenuDefaultItem(UINT uItem = (UINT)-1, BOOL bByPosition = FALSE)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::SetMenuDefaultItem(m_hMenu, uItem, (UINT)bByPosition);
+ }
+
+ BOOL GetMenuItemRect(HWND hWnd, UINT uItem, LPRECT lprcItem) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuItemRect(hWnd, m_hMenu, uItem, lprcItem);
+ }
+
+ int MenuItemFromPoint(HWND hWnd, POINT point) const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::MenuItemFromPoint(hWnd, m_hMenu, point);
+ }
+
+// Context Help Functions
+ BOOL SetMenuContextHelpId(DWORD dwContextHelpId)
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::SetMenuContextHelpId(m_hMenu, dwContextHelpId);
+ }
+
+ DWORD GetMenuContextHelpId() const
+ {
+ ATLASSERT(::IsMenu(m_hMenu));
+ return ::GetMenuContextHelpId(m_hMenu);
+ }
+#endif // !_WIN32_WCE
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAccelerator
+
+template <bool t_bManaged>
+class CAcceleratorT
+{
+public:
+ HACCEL m_hAccel;
+
+// Constructor/destructor/operators
+ CAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel)
+ { }
+
+ ~CAcceleratorT()
+ {
+ if(t_bManaged && m_hAccel != NULL)
+ ::DestroyAcceleratorTable(m_hAccel);
+ }
+
+ CAcceleratorT<t_bManaged>& operator =(HACCEL hAccel)
+ {
+ Attach(hAccel);
+ return *this;
+ }
+
+ void Attach(HACCEL hAccel)
+ {
+ if(t_bManaged && m_hAccel != NULL)
+ ::DestroyAcceleratorTable(m_hAccel);
+ m_hAccel = hAccel;
+ }
+
+ HACCEL Detach()
+ {
+ HACCEL hAccel = m_hAccel;
+ m_hAccel = NULL;
+ return hAccel;
+ }
+
+ operator HACCEL() const { return m_hAccel; }
+
+ bool IsNull() const { return m_hAccel == NULL; }
+
+// Create/destroy methods
+ HACCEL LoadAccelerators(ATL::_U_STRINGorID accel)
+ {
+ ATLASSERT(m_hAccel == NULL);
+ m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), accel.m_lpstr);
+ return m_hAccel;
+ }
+
+ HACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries)
+ {
+ ATLASSERT(m_hAccel == NULL);
+ ATLASSERT(pAccel != NULL);
+ m_hAccel = ::CreateAcceleratorTable(pAccel, cEntries);
+ return m_hAccel;
+ }
+
+ void DestroyObject()
+ {
+ if(m_hAccel != NULL)
+ {
+ ::DestroyAcceleratorTable(m_hAccel);
+ m_hAccel = NULL;
+ }
+ }
+
+// Operations
+#ifndef _WIN32_WCE
+ int CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries)
+ {
+ ATLASSERT(m_hAccel != NULL);
+ ATLASSERT(lpAccelDst != NULL);
+ return ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries);
+ }
+
+ int GetEntriesCount() const
+ {
+ ATLASSERT(m_hAccel != NULL);
+ return ::CopyAcceleratorTable(m_hAccel, NULL, 0);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg)
+ {
+ ATLASSERT(m_hAccel != NULL);
+ ATLASSERT(::IsWindow(hWnd));
+ ATLASSERT(pMsg != NULL);
+ return ::TranslateAccelerator(hWnd, m_hAccel, pMsg);
+ }
+};
+
+typedef CAcceleratorT<false> CAcceleratorHandle;
+typedef CAcceleratorT<true> CAccelerator;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CIcon
+
+template <bool t_bManaged>
+class CIconT
+{
+public:
+ HICON m_hIcon;
+
+// Constructor/destructor/operators
+ CIconT(HICON hIcon = NULL) : m_hIcon(hIcon)
+ { }
+
+ ~CIconT()
+ {
+ if(t_bManaged && m_hIcon != NULL)
+ ::DestroyIcon(m_hIcon);
+ }
+
+ CIconT<t_bManaged>& operator =(HICON hIcon)
+ {
+ Attach(hIcon);
+ return *this;
+ }
+
+ void Attach(HICON hIcon)
+ {
+ if(t_bManaged && m_hIcon != NULL)
+ ::DestroyIcon(m_hIcon);
+ m_hIcon = hIcon;
+ }
+
+ HICON Detach()
+ {
+ HICON hIcon = m_hIcon;
+ m_hIcon = NULL;
+ return hIcon;
+ }
+
+ operator HICON() const { return m_hIcon; }
+
+ bool IsNull() const { return m_hIcon == NULL; }
+
+// Create/destroy methods
+ HICON LoadIcon(ATL::_U_STRINGorID icon)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ m_hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
+ return m_hIcon;
+ }
+
+ HICON LoadIcon(ATL::_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ m_hIcon = (HICON) ::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
+ return m_hIcon;
+ }
+
+#ifndef _WIN32_WCE
+ HICON LoadOEMIcon(LPCTSTR lpstrIconName)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(IsOEMIcon(lpstrIconName));
+ m_hIcon = ::LoadIcon(NULL, lpstrIconName);
+ return m_hIcon;
+ }
+
+ HICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDbits, CONST BYTE *lpbXORbits)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(lpbANDbits != NULL);
+ ATLASSERT(lpbXORbits != NULL);
+ m_hIcon = ::CreateIcon(ModuleHelper::GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits);
+ return m_hIcon;
+ }
+
+ HICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(pBits != NULL);
+ m_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion);
+ return m_hIcon;
+ }
+
+ HICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(pbBits != NULL);
+ ATLASSERT(cbBits > 0);
+ m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags);
+ return m_hIcon;
+ }
+#endif // !_WIN32_WCE
+
+ HICON CreateIconIndirect(PICONINFO pIconInfo)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(pIconInfo != NULL);
+ m_hIcon = ::CreateIconIndirect(pIconInfo);
+ return m_hIcon;
+ }
+
+#ifndef _WIN32_WCE
+ HICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(lpszExeFileName != NULL);
+ m_hIcon = ::ExtractIcon(ModuleHelper::GetModuleInstance(), lpszExeFileName, nIconIndex);
+ return m_hIcon;
+ }
+
+ HICON ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(lpIconPath != NULL);
+ ATLASSERT(lpiIcon != NULL);
+ m_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon);
+ return m_hIcon;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DestroyIcon()
+ {
+ ATLASSERT(m_hIcon != NULL);
+ BOOL bRet = ::DestroyIcon(m_hIcon);
+ if(bRet != FALSE)
+ m_hIcon = NULL;
+ return bRet;
+ }
+
+// Operations
+#ifndef _WIN32_WCE
+ HICON CopyIcon()
+ {
+ ATLASSERT(m_hIcon != NULL);
+ return ::CopyIcon(m_hIcon);
+ }
+
+ HICON DuplicateIcon()
+ {
+ ATLASSERT(m_hIcon != NULL);
+ return ::DuplicateIcon(NULL, m_hIcon);
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DrawIcon(HDC hDC, int x, int y)
+ {
+ ATLASSERT(m_hIcon != NULL);
+#ifndef _WIN32_WCE
+ return ::DrawIcon(hDC, x, y, m_hIcon);
+#else // CE specific
+ return ::DrawIconEx(hDC, x, y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL);
+#endif // _WIN32_WCE
+ }
+
+ BOOL DrawIcon(HDC hDC, POINT pt)
+ {
+ ATLASSERT(m_hIcon != NULL);
+#ifndef _WIN32_WCE
+ return ::DrawIcon(hDC, pt.x, pt.y, m_hIcon);
+#else // CE specific
+ return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL);
+#endif // _WIN32_WCE
+ }
+
+ BOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
+ {
+ ATLASSERT(m_hIcon != NULL);
+ return ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
+ }
+
+ BOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
+ {
+ ATLASSERT(m_hIcon != NULL);
+ return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
+ }
+
+#ifndef _WIN32_WCE
+ BOOL GetIconInfo(PICONINFO pIconInfo) const
+ {
+ ATLASSERT(m_hIcon != NULL);
+ ATLASSERT(pIconInfo != NULL);
+ return ::GetIconInfo(m_hIcon, pIconInfo);
+ }
+
+#if (_WIN32_WINNT >= 0x0600)
+ BOOL GetIconInfoEx(PICONINFOEX pIconInfo) const
+ {
+ ATLASSERT(m_hIcon != NULL);
+ ATLASSERT(pIconInfo != NULL);
+ return ::GetIconInfoEx(m_hIcon, pIconInfo);
+ }
+#endif // (_WIN32_WINNT >= 0x0600)
+
+#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+ HRESULT LoadIconMetric(ATL::_U_STRINGorID icon, int lims)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ USES_CONVERSION;
+ return ::LoadIconMetric(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), lims, &m_hIcon);
+ }
+
+ HRESULT LoadIconWithScaleDown(ATL::_U_STRINGorID icon, int cx, int cy)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ USES_CONVERSION;
+ return ::LoadIconWithScaleDown(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), cx, cy, &m_hIcon);
+ }
+
+ HRESULT LoadOEMIconMetric(LPCTSTR lpstrIconName, int lims)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(IsOEMIcon(lpstrIconName));
+ return ::LoadIconMetric(NULL, (LPCWSTR)lpstrIconName, lims, &m_hIcon);
+ }
+
+ HRESULT LoadOEMIconWithScaleDown(LPCTSTR lpstrIconName, int cx, int cy)
+ {
+ ATLASSERT(m_hIcon == NULL);
+ ATLASSERT(IsOEMIcon(lpstrIconName));
+ USES_CONVERSION;
+ return ::LoadIconWithScaleDown(NULL, (LPCWSTR)lpstrIconName, cx, cy, &m_hIcon);
+ }
+#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)
+#endif // !_WIN32_WCE
+
+ // Helper
+#ifndef _WIN32_WCE
+ static bool IsOEMIcon(LPCTSTR lpstrIconName)
+ {
+#if (WINVER >= 0x0600)
+ return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION ||
+ lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO ||
+ lpstrIconName == IDI_SHIELD);
+#else // !(WINVER >= 0x0600)
+ return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION ||
+ lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO);
+#endif // !(WINVER >= 0x0600)
+ }
+#endif // !_WIN32_WCE
+};
+
+typedef CIconT<false> CIconHandle;
+typedef CIconT<true> CIcon;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCursor
+
+// protect template member from a winuser.h macro
+#ifdef CopyCursor
+ #undef CopyCursor
+#endif
+
+template <bool t_bManaged>
+class CCursorT
+{
+public:
+ HCURSOR m_hCursor;
+
+// Constructor/destructor/operators
+ CCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor)
+ { }
+
+ ~CCursorT()
+ {
+ if(t_bManaged && m_hCursor != NULL)
+ DestroyCursor();
+ }
+
+ CCursorT<t_bManaged>& operator =(HCURSOR hCursor)
+ {
+ Attach(hCursor);
+ return *this;
+ }
+
+ void Attach(HCURSOR hCursor)
+ {
+ if(t_bManaged && m_hCursor != NULL)
+ DestroyCursor();
+ m_hCursor = hCursor;
+ }
+
+ HCURSOR Detach()
+ {
+ HCURSOR hCursor = m_hCursor;
+ m_hCursor = NULL;
+ return hCursor;
+ }
+
+ operator HCURSOR() const { return m_hCursor; }
+
+ bool IsNull() const { return m_hCursor == NULL; }
+
+// Create/destroy methods
+ HCURSOR LoadCursor(ATL::_U_STRINGorID cursor)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ m_hCursor = ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr);
+ return m_hCursor;
+ }
+
+ HCURSOR LoadSysCursor(LPCTSTR lpstrCursorName)
+ {
+ ATLASSERT(m_hCursor == NULL);
+#if (WINVER >= 0x0500)
+ ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT ||
+ lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE ||
+ lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW ||
+ lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL ||
+ lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP ||
+ lpstrCursorName == IDC_HAND);
+#else // !(WINVER >= 0x0500)
+ ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT ||
+ lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE ||
+ lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW ||
+ lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL ||
+ lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP);
+#endif // !(WINVER >= 0x0500)
+ m_hCursor = ::LoadCursor(NULL, lpstrCursorName);
+ return m_hCursor;
+ }
+
+ // deprecated
+ HCURSOR LoadOEMCursor(LPCTSTR lpstrCursorName)
+ {
+ return LoadSysCursor(lpstrCursorName);
+ }
+
+ HCURSOR LoadCursor(ATL::_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ m_hCursor = (HCURSOR) ::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
+ return m_hCursor;
+ }
+
+#ifndef _WIN32_WCE
+ HCURSOR LoadCursorFromFile(LPCTSTR pstrFilename)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ ATLASSERT(pstrFilename != NULL);
+ m_hCursor = ::LoadCursorFromFile(pstrFilename);
+ return m_hCursor;
+ }
+#endif // !_WIN32_WCE
+
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
+ HCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ m_hCursor = ::CreateCursor(ModuleHelper::GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane);
+ return m_hCursor;
+ }
+#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
+
+#ifndef _WIN32_WCE
+ HCURSOR CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ ATLASSERT(pBits != NULL);
+ m_hCursor = (HCURSOR)::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion);
+ return m_hCursor;
+ }
+
+ HCURSOR CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR)
+ {
+ ATLASSERT(m_hCursor == NULL);
+ ATLASSERT(pbBits != NULL);
+ ATLASSERT(cbBits > 0);
+ m_hCursor = (HCURSOR)::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags);
+ return m_hCursor;
+ }
+#endif // !_WIN32_WCE
+
+ BOOL DestroyCursor()
+ {
+ ATLASSERT(m_hCursor != NULL);
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
+ BOOL bRet = ::DestroyCursor(m_hCursor);
+ if(bRet != FALSE)
+ m_hCursor = NULL;
+ return bRet;
+#else // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))))
+ ATLTRACE2(atlTraceUI, 0, _T("Warning: This version of Windows CE does not have ::DestroyCursor()\n"));
+ return FALSE;
+#endif // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))))
+ }
+
+// Operations
+#ifndef _WIN32_WCE
+ HCURSOR CopyCursor()
+ {
+ ATLASSERT(m_hCursor != NULL);
+ return (HCURSOR)::CopyIcon((HICON)m_hCursor);
+ }
+#endif // !_WIN32_WCE
+
+#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+ BOOL GetCursorInfo(LPCURSORINFO pCursorInfo)
+ {
+ ATLASSERT(m_hCursor != NULL);
+ ATLASSERT(pCursorInfo != NULL);
+ return ::GetCursorInfo(pCursorInfo);
+ }
+#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
+};
+
+typedef CCursorT<false> CCursorHandle;
+typedef CCursorT<true> CCursor;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CResource - Wraps a generic Windows resource.
+// Use it with custom resource types other than the
+// standard RT_CURSOR, RT_BITMAP, etc.
+
+class CResource
+{
+public:
+ HGLOBAL m_hGlobal;
+ HRSRC m_hResource;
+
+// Constructor/destructor
+ CResource() : m_hGlobal(NULL), m_hResource(NULL)
+ { }
+
+ ~CResource()
+ {
+ Release();
+ }
+
+// Load methods
+ bool Load(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID)
+ {
+ ATLASSERT(m_hResource == NULL);
+ ATLASSERT(m_hGlobal == NULL);
+
+ m_hResource = ::FindResource(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr);
+ if(m_hResource == NULL)
+ return false;
+
+ m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource);
+ if(m_hGlobal == NULL)
+ {
+ m_hResource = NULL;
+ return false;
+ }
+
+ return true;
+ }
+
+#ifndef _WIN32_WCE
+ bool LoadEx(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID, WORD wLanguage)
+ {
+ ATLASSERT(m_hResource == NULL);
+ ATLASSERT(m_hGlobal == NULL);
+
+ m_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr, wLanguage);
+ if(m_hResource == NULL)
+ return false;
+
+ m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource);
+ if(m_hGlobal == NULL)
+ {
+ m_hResource = NULL;
+ return false;
+ }
+
+ return true;
+ }
+#endif // !_WIN32_WCE
+
+// Misc. operations
+ DWORD GetSize() const
+ {
+ ATLASSERT(m_hResource != NULL);
+ return ::SizeofResource(ModuleHelper::GetResourceInstance(), m_hResource);
+ }
+
+ LPVOID Lock()
+ {
+ ATLASSERT(m_hResource != NULL);
+ ATLASSERT(m_hGlobal != NULL);
+ LPVOID pVoid = ::LockResource(m_hGlobal);
+ ATLASSERT(pVoid != NULL);
+ return pVoid;
+ }
+
+ void Release()
+ {
+ if(m_hGlobal != NULL)
+ {
+ FreeResource(m_hGlobal);
+ m_hGlobal = NULL;
+ m_hResource = NULL;
+ }
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Toolbar resource descriptor
+
+struct _AtlToolBarData
+{
+ WORD wVersion;
+ WORD wWidth;
+ WORD wHeight;
+ WORD wItemCount;
+
+ WORD* items()
+ { return (WORD*)(this+1); }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global functions for loading resources
+
+inline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table)
+{
+ return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_lpstr);
+}
+
+inline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu)
+{
+ return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);
+}
+
+inline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap)
+{
+ return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr);
+}
+
+#ifdef OEMRESOURCE
+inline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap)
+{
+#ifdef _DEBUG
+ WORD wID = (WORD)bitmap.m_lpstr;
+ ATLASSERT(wID >= 32734 && wID <= 32767);
+#endif // _DEBUG
+ return ::LoadBitmap(NULL, bitmap.m_lpstr);
+}
+#endif // OEMRESOURCE
+
+inline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor)
+{
+ return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr);
+}
+
+inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName)
+{
+#if (WINVER >= 0x0500)
+ ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT ||
+ lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE ||
+ lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW ||
+ lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL ||
+ lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP ||
+ lpCursorName == IDC_HAND);
+#else // !(WINVER >= 0x0500)
+ ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT ||
+ lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE ||
+ lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW ||
+ lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL ||
+ lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP);
+#endif // !(WINVER >= 0x0500)
+ return ::LoadCursor(NULL, lpCursorName);
+}
+
+inline HICON AtlLoadIcon(ATL::_U_STRINGorID icon)
+{
+ return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
+}
+
+#ifndef _WIN32_WCE
+inline HICON AtlLoadSysIcon(LPCTSTR lpIconName)
+{
+#if (WINVER >= 0x0600)
+ ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION ||
+ lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO ||
+ lpIconName == IDI_SHIELD);
+#else // !(WINVER >= 0x0600)
+ ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION ||
+ lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO);
+#endif // !(WINVER >= 0x0600)
+ return ::LoadIcon(NULL, lpIconName);
+}
+#endif // !_WIN32_WCE
+
+inline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR)
+{
+ return (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad);
+}
+
+inline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
+{
+ return (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
+}
+
+inline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
+{
+ return (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
+}
+
+#ifdef OEMRESOURCE
+inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR)
+{
+ ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767);
+ ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
+ return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad);
+}
+#endif // OEMRESOURCE
+
+inline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
+{
+#ifdef _DEBUG
+ WORD wID = (WORD)cursor.m_lpstr;
+ ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651));
+ ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
+#endif // _DEBUG
+ return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
+}
+
+inline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
+{
+#ifdef _DEBUG
+ WORD wID = (WORD)icon.m_lpstr;
+ ATLASSERT(wID >= 32512 && wID <= 32517);
+ ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
+#endif // _DEBUG
+ return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
+}
+
+#if (_ATL_VER < 0x0700)
+inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax)
+{
+ return ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpBuffer, nBufferMax);
+}
+#else
+
+using ATL::AtlLoadString;
+
+#endif // (_ATL_VER < 0x0700)
+
+#ifdef _WIN32_WCE // CE only direct access to the resource
+inline LPCTSTR AtlLoadString(UINT uID)
+{
+ LPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), uID, NULL, 0);
+#ifdef DEBUG // Check for null-termination
+ if(s != NULL)
+ // Note: RC -n <file.rc> compiles null-terminated resource strings
+ ATLASSERT(s[*((WORD*)s -1) - 1] == L'\0');
+#endif
+ return s;
+}
+#endif // _WIN32_WCE
+
+inline bool AtlLoadString(UINT uID, BSTR& bstrText)
+{
+ USES_CONVERSION;
+ ATLASSERT(bstrText == NULL);
+
+ LPTSTR lpstrText = NULL;
+ int nRes = 0;
+ for(int nLen = 256; ; nLen *= 2)
+ {
+ ATLTRY(lpstrText = new TCHAR[nLen]);
+ if(lpstrText == NULL)
+ break;
+ nRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpstrText, nLen);
+ if(nRes < nLen - 1)
+ break;
+ delete [] lpstrText;
+ lpstrText = NULL;
+ }
+
+ if(lpstrText != NULL)
+ {
+ if(nRes != 0)
+ bstrText = ::SysAllocString(T2OLE(lpstrText));
+ delete [] lpstrText;
+ }
+
+ return (bstrText != NULL) ? true : false;
+}
+
+}; // namespace WTL
+
+#endif // __ATLUSER_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLWINCE_H__
+#define __ATLWINCE_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlwince.h requires atlapp.h to be included first
+#endif
+
+#ifndef __ATLWIN_H__
+ #error atlwince.h requires atlwin.h to be included first
+#endif
+
+#ifndef _WIN32_WCE
+ #error atlwince.h compiles under Windows CE only
+#endif
+
+#if (_WIN32_WCE < 300)
+ #error atlwince.h requires Windows CE 3.0 or higher.
+#endif
+
+#if defined(WIN32_PLATFORM_WFSP) && _MSC_VER < 1400 // EVC compiling SmartPhone code
+ #if (WIN32_PLATFORM_WFSP < 200)
+ #error atlwince.h requires Smartphone 2003 or higher
+ #endif
+#endif // WIN32_PLATFORM_WFSP
+
+#if defined(WIN32_PLATFORM_PSPC) && _MSC_VER < 1400 // EVC compiling Pocket PC code
+ #if (WIN32_PLATFORM_PSPC < 310)
+ #error atlwince.h requires Pocket PC 2002 or higher
+ #endif
+#endif // WIN32_PLATFORM_PSPC
+
+#if !defined(_AYGSHELL_H_) && !defined(__AYGSHELL_H__)
+ #error atlwince.h requires aygshell.h to be included first
+#else
+ #if defined(WIN32_PLATFORM_WFSP) && !defined(_TPCSHELL_H_)
+ #error SmartPhone dialog classes require tpcshell.h to be included first
+ #endif
+#endif
+
+#if (_MSC_VER >= 1400) // VS2005
+ #include <DeviceResolutionAware.h>
+ #define _WTL_CE_DRA
+#endif // (_MSC_VER >= 1400)
+
+#if !defined(_WTL_CE_NO_DIALOGS) && !defined(__ATLFRAME_H__)
+ #error Orientation aware dialog classes require atlframe.h to be included first
+#endif
+
+#if !defined(_WTL_CE_NO_APPWINDOW) && !defined(__ATLFRAME_H__)
+ #error Application window class require atlframe.h to be included first
+#endif
+
+#if !defined(_WTL_CE_NO_ZOOMSCROLL) && !defined(__ATLSCRL_H__)
+ #error ZoomScroll implementation requires atlscrl.h to be included first
+#endif
+
+#if !defined(_WTL_CE_NO_ZOOMSCROLL)
+ #if !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES)))
+ #error ZoomScroll requires _WTL_NO_WTYPES not to be defined and either atlmisc.h or atltypes.h to be included first
+ #endif // !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES)))
+#endif // !defined(_WTL_CE_NO_ZOOMSCROLL)
+
+#if !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC)
+ #define _WTL_CE_NO_CONTROLS
+#endif // !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC)
+
+#ifndef _WTL_CE_NO_CONTROLS
+ #ifndef __ATLCTRLS_H__
+ #error The PPC/SmartPhone controls classes require atlctrls.h to be included first
+ #endif
+
+ #include <htmlctrl.h>
+ #pragma comment(lib, "htmlview.lib")
+
+ #include <voicectl.h>
+ #pragma comment(lib, "voicectl.lib")
+
+ #ifdef WIN32_PLATFORM_PSPC
+ #include <richink.h>
+ #pragma comment(lib, "richink.lib")
+
+ #include <inkx.h>
+ #pragma comment(lib, "inkx.lib")
+
+ #include <doclist.h>
+ #pragma comment(lib, "doclist.lib")
+ #endif
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// CStdDialogBase<T, t_shidiFlags, t_bModal> : Standard PPC/SmartPhone dialog base class
+// CStdDialogImplBase - Base implementation of standard dialog
+// CStdDialogImpl<T, t_shidiFlags, t_bModal> : Standard dialog implementation
+// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog
+// CStdAxDialogImpl<T, t_shidiFlags, t_bModal> : Standard AxDialog implementation
+// CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags> : Standard simple dialog
+// CStdDialogResizeImplBase - Base implementation of orientation resizing standard dialog
+// CStdDialogResizeImpl<T, t_shidiFlags, t_bModal> : Orientation resizing standard dialog implementation
+// CStdAxDialogResizeImpl - implementation of orientation resizing standard AxDialog
+// CStdSimpleDialogResizeImpl<T, t_wDlgTemplateID, t_shidiFlags> : Standard resizing simple dialog implementation
+// CStdOrientedDialogBase - Oriented PPC standard dialog base class
+// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation
+// CStdOrientedDialogImpl<T, t_shidiFlags, t_bModal> : Oriented PPC standard dialog implementation
+// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation
+// CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> : Standard simple orientable dialog
+//
+// CAppInfoBase : Helper for application state save/restore to registry
+// CAppInfoT<T> : CAppInfoBase constructed from a CAppWindow<T>
+// CAppWindowBase<T> : Base class for PPC/SmartPhone well-behaved application window or dialog
+// CAppWindow<T> : PPC/SmartPhone well-behaved application window class
+// CAppDialog<T> : PPC/SmartPhone well-behaved application dialog class
+// CAppStdDialogImplBase - Base implementation of standard application dialogs
+// CAppStdDialogImpl<T, t_shidiFlags, t_bModal> : Implementation of standard application dialog
+// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog
+// CAppStdAxDialogImpl - Implementation of standard application AxDialog
+// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog
+// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog
+// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog
+//
+// CFullScreenFrame<T, t_bHasSip> : Full screen frame class
+//
+// CZoomScrollImpl<T> : WinCE zooming implementation
+//
+// CBottomTabViewImpl<T, TBase, TWinTraits> - CBottomTabView
+// CHtmlCtrlT<TBase> - CHtmlCtrl
+// CRichInkCtrlT<TBase> - CRichInkCtrl
+// CInkXCtrlT<TBase> - CInkXCtrl
+// CVoiceRecorderCtrlT<TBase> - CVoiceRecorderCtrl
+// CDocListCtrlT<TBase> - CDocListCtrl
+// CCapEditT<TBase> - CCapEdit
+// CTTStaticT<TBase> - CTTStatic
+// CTTButtonT<TBase> - CTTButton
+//
+// CSpinCtrlT<TBase> - CSpinCtrl : SmartPhone specific UpDown control
+// CSpinned<TBase, t_bExpandOnly> : SmartPhone association of control and Spin
+// CSpinListBox : SmartPhone spinned ListBox control
+// CExpandListBox : SmartPhone expandable ListBox control
+// CExpandEdit : SmartPhone expandable Edit control
+// CExpandCapEdit : SmartPhone expandable CapEdit control
+//
+// Global functions:
+// AtlCreateMenuBar()
+// AtlCreateEmptyMenuBar()
+// AtlIsEditFocus()
+// AtlActivateBackKey()
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// MenuBar creation functions for property sheets and dialogs
+// Frame windows use CreateSimpleCEMenuBar
+
+inline HWND AtlCreateMenuBar(SHMENUBARINFO& mbi)
+{
+ ATLASSERT(::IsWindow(mbi.hwndParent));
+ ATLVERIFY(::SHCreateMenuBar(&mbi) != FALSE);
+ return mbi.hwndMB;
+};
+
+inline HWND AtlCreateMenuBar(HWND hWnd, UINT nToolBarId = ATL_IDW_TOOLBAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0, COLORREF clrBk = 0)
+{
+ SHMENUBARINFO mbi = { sizeof(mbi), hWnd, dwFlags, nToolBarId, ModuleHelper::GetResourceInstance(), nBmpId, cBmpImages, 0, clrBk };
+ return AtlCreateMenuBar(mbi);
+}
+
+inline HWND AtlCreateEmptyMenuBar(HWND hWnd, bool bSip = true)
+{
+ SHMENUBARINFO embi = { sizeof(SHMENUBARINFO), hWnd, SHCMBF_EMPTYBAR };
+ if (!bSip)
+ embi.dwFlags |= SHCMBF_HIDESIPBUTTON;
+
+ return AtlCreateMenuBar(embi);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper functions for SmartPhone back key handling
+
+inline bool AtlIsEditFocus()
+{
+ ATL::CWindow wCtrl = GetFocus();
+ if (wCtrl.IsWindow())
+ {
+ TCHAR szClassName[8] = {0};
+ ATLVERIFY(::GetClassName(wCtrl.m_hWnd, szClassName, 8));
+ return !_tcscmp(szClassName, _T("Edit")) || !_tcscmp(szClassName, WC_CAPEDIT);
+ }
+ return false;
+}
+
+#if defined WIN32_PLATFORM_WFSP
+inline void AtlActivateBackKey(HWND hMenuBar)
+{
+ ATLASSERT(::IsWindow(hMenuBar));
+ ::SendMessage(hMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK,
+ MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
+}
+#endif // WIN32_PLATFORM_WFSP
+
+// --- Standard PPC/SmartPhone dialogs ---
+
+#ifndef _WTL_CE_NO_DIALOGS
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogBase - base class for standard PPC/SmartPhone dialogs
+
+#define WTL_STD_SHIDIF SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN
+#define WTL_SP_SHIDIF SHIDIF_SIZEDLGFULLSCREEN
+
+// Title setting macros
+#define WTL_DLG_TITLEHEIGHT(iHeight) static const int GetTitleHeight(){return iHeight;}
+#define WTL_DLG_NOTITLE WTL_DLG_TITLEHEIGHT(0)
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogBase - Base class for standard PPC/SmartPhone dialog
+
+template <class T, UINT t_shidiFlags, bool t_bModal = true>
+class CStdDialogBase
+{
+public:
+#ifdef WIN32_PLATFORM_PSPC
+// Pocket PC only Dialog title handling
+ const int nTitleHeight;
+
+ CStdDialogBase() : nTitleHeight(T::GetTitleHeight())
+ { }
+
+// Overloads
+ BOOL GetClientRect(LPRECT lpRect)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ BOOL bRes = ::GetClientRect(pT->m_hWnd, lpRect);
+ if (nTitleHeight)
+ lpRect->top += nTitleHeight + 1;
+ return bRes;
+ }
+
+ BOOL SetWindowText(LPCTSTR lpszString)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ BOOL bRes = ::SetWindowText(pT->m_hWnd, lpszString);
+ if (nTitleHeight != 0)
+ pT->DoPaintTitle();
+ return bRes;
+ }
+
+// Overrideables
+ static const int GetTitleHeight()
+ {
+ #ifdef _WTL_CE_DRA
+ return DRA::SCALEY(24);
+ #else // !_WTL_CE_DRA
+ CWindowDC dc(NULL);
+ return dc.GetDeviceCaps(LOGPIXELSY) >> 2; // LOGPIXELSY * 24 / 96,
+ #endif // !_WTL_CE_DRA
+ }
+
+ // Title painting
+ bool DoPaintTitle()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ TCHAR sTitle[48];
+
+ // Preparation
+ CPaintDC dc(pT->m_hWnd);
+ CFont fontTitle = AtlCreateBoldFont();
+ CFontHandle fontOld = dc.SelectFont(fontTitle);
+ dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT));
+ int nLen = pT->GetWindowText(sTitle, 48);
+ int nWidth = dc.GetDeviceCaps(HORZRES);
+
+ // Display title text
+ RECT rTitle = { 0, 0, nWidth, nTitleHeight };
+ dc.FillRect(&rTitle, COLOR_3DHIGHLIGHT);
+ #ifdef _WTL_CE_DRA
+ rTitle.left = DRA::SCALEX(8);
+ #else // !_WTL_CE_DRA
+ rTitle.left = nTitleHeight / 3; // 8 == 24 / 3
+ #endif // !_WTL_CE_DRA
+ dc.DrawText(sTitle, nLen, &rTitle, DT_VCENTER | DT_SINGLELINE);
+ dc.SelectFont(fontOld);
+
+ // Draw bottom line, 2 pixels thick if HI_RES_AWARE
+ CPenHandle penOld = dc.SelectStockPen(BLACK_PEN);
+ POINT line[4] = {{0, nTitleHeight}, {nWidth, nTitleHeight}, {0, nTitleHeight - 1}, {nWidth, nTitleHeight - 1}};
+
+ #ifdef _WTL_CE_DRA
+ int nSeg = DRA::SCALEY(1);
+ #else // !_WTL_CE_DRA
+ int nSeg = nTitleHeight / 24;
+ #endif // !_WTL_CE_DRA
+
+ dc.Polyline(line, nSeg <= 2 ? nSeg * 2 : 4);
+ dc.SelectPen(penOld);
+
+ return false;
+ }
+
+ // Title preparation: move the dialog controls down to make room for title
+ void DialogTitleInit()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+
+ ATL::CWindow wCtl = pT->GetWindow(GW_CHILD);
+ while (wCtl.IsWindow())
+ {
+ RECT rCtl = { 0 };
+ wCtl.GetWindowRect(&rCtl);
+ ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rCtl, 2);
+ ::OffsetRect(&rCtl, 0, nTitleHeight);
+ wCtl.MoveWindow(&rCtl, FALSE);
+ wCtl = wCtl.GetWindow(GW_HWNDNEXT);
+ }
+ }
+
+ // SIP management
+ void DoSipInfo()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+
+ SIPINFO si = {sizeof(SIPINFO)};
+ SipGetInfo(&si);
+ if ((si.fdwFlags & SIPF_ON) ^ SIPF_ON)
+ si.rcVisibleDesktop.bottom = si.rcSipRect.bottom;
+ pT->MoveWindow(&si.rcVisibleDesktop, FALSE);
+ }
+
+// Title painting handler
+ LRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ return bHandled = nTitleHeight ? pT->DoPaintTitle() : FALSE;
+ }
+
+// SIP handler
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ if (wParam == SPI_SETSIPINFO)
+ {
+ pT->DoSipInfo();
+ return TRUE;
+ }
+ return bHandled = FALSE;
+ }
+
+#elif defined WIN32_PLATFORM_WFSP
+// SmartPhone VK_TBACK key standard management
+ LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ const UINT uModif = (UINT)LOWORD(lParam);
+ const UINT uVirtKey = (UINT)HIWORD(lParam);
+
+ if(uVirtKey == VK_TBACK)
+ if (AtlIsEditFocus())
+ ::SHSendBackToFocusWindow(uMsg, wParam, lParam);
+ else if (uModif & MOD_KEYUP)
+ pT->StdCloseDialog(IDCANCEL);
+ return 1;
+ }
+
+ // SmartPhone MenuBar and VK_TBACK key initialization
+ void StdSPInit()
+ {
+ T* pT = static_cast<T*>(this);
+ HWND hMenuBar = ::SHFindMenuBar(pT->m_hWnd);
+
+ if (!hMenuBar && (t_shidiFlags & SHIDIF_DONEBUTTON))
+ hMenuBar = CreateMenuBar(ATL_IDM_MENU_DONE);
+
+ if(hMenuBar != NULL)
+ AtlActivateBackKey(hMenuBar);
+ }
+
+ void SetStaticBold()
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+
+ CFontHandle fontBold = AtlCreateBoldFont(pT->GetFont());
+
+ ATL::CWindow wCtl = pT->GetWindow(GW_CHILD);
+
+ while (wCtl.IsWindow())
+ {
+ if ((short int)wCtl.GetDlgCtrlID() == IDC_STATIC)
+ wCtl.SetFont(fontBold);
+ wCtl = wCtl.GetWindow(GW_HWNDNEXT);
+ }
+ }
+#endif // WIN32_PLATFORM_WFSP
+
+// Platform dependant initialization
+ void StdPlatformInit()
+ {
+ T* pT = static_cast<T*>(this);
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC title initialization
+ if (nTitleHeight != 0)
+ pT->DialogTitleInit();
+#elif defined(WIN32_PLATFORM_WFSP)
+ pT->StdSPInit();
+ SetStaticBold();
+#endif // WIN32_PLATFORM_WFSP
+ }
+
+ // Menu bar creation
+ HWND CreateMenuBar(UINT uiMB = T::IDD, int nBmpImages = 0)
+ {
+ T* pT = static_cast<T*>(this);
+ return AtlCreateMenuBar(pT->m_hWnd, uiMB, 0, nBmpImages ? uiMB : 0, nBmpImages);
+ }
+
+ // Dialog closing
+ void StdCloseDialog(WORD wID)
+ {
+ T* pT = static_cast<T*>(this);
+ if (t_bModal)
+ ::EndDialog(pT->m_hWnd, wID);
+ else
+ pT->DestroyWindow();
+ }
+
+ // Shell dialog layout initialization
+ void StdShidInit()
+ {
+ T* pT = static_cast<T*>(this);
+ SHINITDLGINFO shidi = { SHIDIM_FLAGS, pT->m_hWnd, t_shidiFlags };
+ ::SHInitDialog(&shidi);
+ }
+
+// IDC_INFOSTATIC background setting
+ LRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ if (::GetDlgCtrlID((HWND)lParam) == IDC_INFOSTATIC)
+ {
+ ::SetBkMode((HDC)wParam, TRANSPARENT);
+ return (LRESULT)::GetSysColorBrush(COLOR_INFOBK);
+ }
+ return bHandled = FALSE;
+ }
+
+// Menu dialog ending
+ LRESULT OnMenuClose(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->StdCloseDialog((WORD)(wID - ID_MENU_OK + IDOK));
+ return 0;
+ }
+
+// Standard dialog ending: may be used with any command
+ LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->StdCloseDialog(wID);
+ return 0;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogImplBase - Base implementation of standard PPC/SmartPhone dialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl< T > >
+class ATL_NO_VTABLE CStdDialogImplBase :
+ public TBase,
+ public CStdDialogBase<T, t_shidiFlags, t_bModal>
+{
+public:
+#ifdef WIN32_PLATFORM_PSPC
+ BOOL GetClientRect(LPRECT lpRect)
+ {
+ return CStdDialogBase<T, t_shidiFlags, t_bModal>::GetClientRect(lpRect);
+ }
+
+ BOOL SetWindowText(LPCTSTR lpszString)
+ {
+ return CStdDialogBase<T, t_shidiFlags, t_bModal>::SetWindowText(lpszString);
+ }
+#endif
+
+ BEGIN_MSG_MAP(CStdDialogImplBase)
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key
+ MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
+#endif
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _DEBUG
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(t_bModal == pT->m_bModal);
+#endif
+ StdPlatformInit();
+ StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogImpl - implementation of standard PPC/SmartPhone dialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal>
+{};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog
+
+#if defined __ATLDLGS_H__
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true>
+class ATL_NO_VTABLE CStdIndirectDialogImpl :
+ public CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl<T, t_shidiFlags, t_bModal> >
+{
+public:
+ typedef CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl<T, t_shidiFlags, t_bModal> > _baseClass;
+ typedef CStdDialogImpl<T, t_shidiFlags, t_bModal> _baseStd;
+
+ void CheckStyle()
+ {
+ // Mobile devices don't support DLGTEMPLATEEX
+ ATLASSERT(!m_Template.IsTemplateEx());
+
+ // Standard dialogs need only DS_CENTER
+ DWORD &dwStyle = m_Template.GetTemplatePtr()->style;
+ if (dwStyle & DS_CENTER)
+ if(t_bModal)
+ {
+ ATLASSERT((dwStyle & WS_CHILD) != WS_CHILD);
+ dwStyle |= WS_POPUP;
+ }
+ else
+ {
+ if((dwStyle & WS_CHILD) != WS_CHILD)
+ dwStyle |= WS_POPUP;
+ }
+ }
+
+ INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
+ {
+ ATLASSERT(t_bModal);
+
+ if (!m_Template.IsValid())
+ CreateTemplate();
+
+ CheckStyle();
+
+ return _baseClass::DoModal(hWndParent, dwInitParam);
+ }
+
+ HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
+ {
+ ATLASSERT(!t_bModal);
+
+ if (!m_Template.IsValid())
+ CreateTemplate();
+
+ CheckStyle();
+
+ return _baseClass::Create(hWndParent, dwInitParam);
+ }
+
+ BEGIN_MSG_MAP(CStdIndirectDialogImpl)
+ CHAIN_MSG_MAP(_baseStd)
+ END_MSG_MAP()
+
+};
+
+#endif // defined __ATLDLGS_H__
+
+#ifndef _ATL_NO_HOSTING
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdAxDialogImpl - implementation of standard PPC/SmartPhone AxDialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdAxDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl< T > >
+{};
+#endif // _ATL_NO_HOSTING
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdSimpleDialog - standard PPC/SmartPhone simple dialog with SHIDIF_xxx flags
+
+template <WORD t_wDlgTemplateID, UINT t_shidiFlags = WTL_STD_SHIDIF>
+class CStdSimpleDialog :
+ public ATL::CSimpleDialog<t_wDlgTemplateID, FALSE>,
+ public CStdDialogBase<CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>, t_shidiFlags>
+{
+public:
+ typedef CStdDialogBase<CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>, t_shidiFlags> baseClass;
+
+#ifdef WIN32_PLATFORM_PSPC
+ BOOL GetClientRect(LPRECT lpRect)
+ {
+ return baseClass::GetClientRect(lpRect);
+ }
+
+ BOOL SetWindowText(LPCTSTR lpszString)
+ {
+ return baseClass::SetWindowText(lpszString);
+ }
+#endif
+
+ BEGIN_MSG_MAP(CStdSimpleDialog)
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key
+ MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
+#endif
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ StdPlatformInit();
+ StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogResizeImplBase - Base implementation of orientation resizing standard PPC/SmartPhone dialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl<T> >
+class ATL_NO_VTABLE CStdDialogResizeImplBase :
+ public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>,
+ public CDialogResize<T>
+{
+public:
+ // Note: BEGIN_DLGRESIZE_MAP is required in the derived class.
+
+ BEGIN_MSG_MAP(CStdResizeDialogImplBase)
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC title
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key
+ MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
+#endif
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ CHAIN_MSG_MAP(CDialogResize< T >)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifdef _DEBUG
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(t_bModal == pT->m_bModal);
+#endif
+ StdPlatformInit();
+ DlgResize_Init(FALSE);
+ StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone dialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal>
+{};
+
+#ifndef _ATL_NO_HOSTING
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdAxDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone AxDialog
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdAxDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl<T> >
+{};
+#endif // _ATL_NO_HOSTING
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdSimpleDialogResizeImpl - implementation of standard resizing simple dialog with SHIDIF_xxx flags
+
+// Usage:
+// class CMyDlg : public CStdSimpleDialogResize<CMyDlg,
+// IDD_MYDLG, SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR>
+// {
+// public:
+// BEGIN_DLGRESIZE_MAP(CMyDlg)
+// ...
+// END_DLGRESIZE_MAP()
+// };
+
+template <class T, WORD t_wDlgTemplateID, UINT t_shidiFlags = WTL_STD_SHIDIF>
+class ATL_NO_VTABLE CStdSimpleDialogResizeImpl :
+ public CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>,
+ public CDialogResize< T >
+{
+public:
+ typedef CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>::baseClass baseClass;
+
+ BEGIN_MSG_MAP(CStdSimpleDialogResizeImpl)
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC title
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key
+ MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
+#endif
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ CHAIN_MSG_MAP(CDialogResize< T >)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ StdPlatformInit();
+ DlgResize_Init(FALSE);
+ StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdOrientedDialogBase - Oriented PPC standard dialog base class
+
+template <class T>
+class CStdOrientedDialogBase
+{
+public:
+// Operation
+ BOOL SetOrientation(DRA::DisplayMode mode)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ ATLASSERT(mode == DRA::GetDisplayMode());
+
+ // Derived dialog must enumerate TWO dialog templates with the same control ids and types ie:
+ // enum { IDD = IDD_MYDLG, IDD_LANDSCAPE = IDD_MYDLG_L };
+ UINT iResource = (mode == DRA::Landscape)? T::IDD_LANDSCAPE : T::IDD;
+
+ BOOL bRes = DRA::RelayoutDialog(ModuleHelper::GetResourceInstance(), pT->m_hWnd, MAKEINTRESOURCE(iResource));
+ pT->OnOrientation(mode);
+ return bRes;
+ }
+
+// Override
+ void OnOrientation(DRA::DisplayMode /*mode*/)
+ {}
+
+// Message handlers
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ if (wParam == SETTINGCHANGE_RESET)
+ {
+ SetOrientation(DRA::GetDisplayMode());
+ pT->StdPlatformInit();
+ pT->StdShidInit();
+ }
+ else if (wParam == SPI_SETSIPINFO)
+ {
+ pT->DoSipInfo();
+ return TRUE;
+ }
+ return bHandled = FALSE;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl<T> >
+class ATL_NO_VTABLE CStdOrientedDialogImplBase :
+ public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>,
+ public CStdOrientedDialogBase<T>
+{
+public:
+ BEGIN_MSG_MAP(CStdOrientedDialogImpl)
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, CStdOrientedDialogBase<T>::OnSettingChange)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+#ifdef _DEBUG
+ ATLASSERT(t_bModal == pT->m_bModal);
+#endif
+ if (DRA::GetDisplayMode() == DRA::Landscape)
+ SetOrientation(DRA::Landscape);
+ pT->StdPlatformInit();
+ pT->StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdOrientedDialogImpl - Oriented PPC standard dialog implementation
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal>
+{};
+
+#ifndef _ATL_NO_HOSTING
+///////////////////////////////////////////////////////////////////////////////
+// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation
+
+template <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >
+class ATL_NO_VTABLE CStdAxOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl<T> >
+{};
+#endif // _ATL_NO_HOSTING
+
+///////////////////////////////////////////////////////////////////////////////
+// CStdSimpleOrientedDialog - Standard simple orientable dialog
+
+template <WORD t_wDlgTemplateID, WORD t_wDlgLandscapeID, UINT t_shidiFlags = WTL_STD_SHIDIF>
+class CStdSimpleOrientedDialog :
+ public CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>,
+ public CStdOrientedDialogBase<CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> >
+{
+public:
+ typedef CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>::baseClass baseClass;
+ typedef CStdOrientedDialogBase<CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> > baseOriented;
+
+ enum {IDD = t_wDlgTemplateID, IDD_LANDSCAPE = t_wDlgLandscapeID};
+
+ BEGIN_MSG_MAP(CStdSimpleDialog)
+ MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
+ MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, baseOriented::OnSettingChange)
+ MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)
+ COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)
+ END_MSG_MAP()
+
+ LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if (DRA::GetDisplayMode() == DRA::Landscape)
+ SetOrientation(DRA::Landscape);
+ StdPlatformInit();
+ StdShidInit();
+ return bHandled = FALSE;
+ }
+};
+
+#endif // _WTL_CE_DRA
+
+
+#endif // _WTL_CE_NO_DIALOGS
+
+
+// --- PPC/SmartPhone application window and helpers ---
+
+#ifndef _WTL_CE_NO_APPWINDOW
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppInfoBase - Helper for application state save/restore to registry
+
+class CAppInfoBase
+{
+public:
+ CRegKeyEx m_Key;
+
+ CAppInfoBase(ATL::_U_STRINGorID sAppKey)
+ {
+ m_Key.Create(HKEY_CURRENT_USER, sAppKey.m_lpstr);
+ ATLASSERT(m_Key.m_hKey);
+ }
+
+ template <class V>
+ LONG Save(V& val, ATL::_U_STRINGorID sName)
+ {
+ return m_Key.SetBinaryValue(sName.m_lpstr, &val, sizeof(V));
+ }
+
+ template <class V>
+ LONG Save(int nb, V& val0, ATL::_U_STRINGorID sName)
+ {
+ return m_Key.SetBinaryValue(sName.m_lpstr, &val0, nb * sizeof(V));
+ }
+
+ template <class V>
+ LONG Restore(V& val, ATL::_U_STRINGorID sName)
+ {
+ ULONG bufSize = sizeof(V);
+ return m_Key.QueryBinaryValue(sName.m_lpstr, &val, &bufSize);
+ }
+
+ template <class V>
+ LONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName)
+ {
+ ULONG bufSize = nb * sizeof(V);
+ return m_Key.QueryBinaryValue(sName.m_lpstr, &val0, &bufSize);
+ }
+
+#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+ LONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName)
+ {
+ return m_Key.SetStringValue(sName.m_lpstr, sval);
+ }
+
+ LONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName)
+ {
+ DWORD size = MAX_PATH;
+ LONG res = m_Key.QueryStringValue(sName.m_lpstr, sval.GetBuffer(size), &size);
+ sval.ReleaseBuffer();
+ return res;
+ }
+#else
+ #pragma message("Warning: CAppInfoBase compiles without CString support. Do not use CString in Save or Restore.")
+#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
+
+ LONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName)
+ {
+ return m_Key.SetStringValue(sName.m_lpstr, sval);
+ }
+
+ LONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength)
+ {
+ return m_Key.QueryStringValue(sName.m_lpstr, sval, plength);
+ }
+
+ LONG Delete(ATL::_U_STRINGorID sName)
+ {
+ return m_Key.DeleteValue(sName.m_lpstr);
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppInfoT - CAppInfoBase constructed from a class with T::GetAppKey()
+
+// Macro for declaring AppKey
+#define DECLARE_APPKEY(uAppKey) \
+ static LPCTSTR GetAppKey() \
+ { \
+ static LPCTSTR sAppKey = ATL::_U_STRINGorID(uAppKey).m_lpstr; \
+ return sAppKey; \
+ }
+
+template <class T>
+class CAppInfoT : public CAppInfoBase
+{
+public:
+ CAppInfoT() : CAppInfoBase(T::GetAppKey()){}
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppWindowBase - Base class for PPC/SmartPhone "well-behaved" application window or dialog
+
+// Macros for declaring frame WNDCLASS and AppKey
+#define DECLARE_APP_FRAME_CLASS(WndClassName, uCommonResourceID, uAppKey) \
+ DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
+ DECLARE_APPKEY(uAppKey)
+
+#define DECLARE_APP_FRAME_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd, uAppKey) \
+ DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
+ DECLARE_APPKEY(uAppKey)
+
+template <class T>
+class CAppWindowBase
+{
+public:
+ typedef class CAppInfoT< T > CAppInfo;
+
+#ifndef WIN32_PLATFORM_WFSP
+ SHACTIVATEINFO m_sai; // NoOp on SmartPhones
+#endif // WIN32_PLATFORM_WFSP
+
+ bool m_bHibernate;
+
+ CAppWindowBase< T >() : m_bHibernate(false)
+ {
+#ifndef WIN32_PLATFORM_WFSP
+ SHACTIVATEINFO sai = { sizeof(SHACTIVATEINFO) };
+ m_sai = sai;
+#endif // WIN32_PLATFORM_WFSP
+ };
+
+ // Same as WTL 7.1 AppWizard generated ActivatePreviousInstance + SendMessage WM_COPYDATA
+ static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine, bool bDialog)
+ {
+ // requires T does DECLARE_APP_FRAME_CLASS, DECLARE_APP_FRAME_CLASS_EX or DECLARE_APP_DLG_CLASS
+ CFrameWndClassInfo& classInfo = T::GetWndClassInfo();
+
+ ATLVERIFY(::LoadString(hInstance, classInfo.m_uCommonResourceID, classInfo.m_szAutoName, sizeof(classInfo.m_szAutoName)/sizeof(classInfo.m_szAutoName[0])) != 0);
+
+ classInfo.m_wc.lpszClassName = classInfo.m_szAutoName;
+
+ const TCHAR* pszClass = classInfo.m_wc.lpszClassName;
+
+ if(NULL == pszClass || '\0' == *pszClass)
+ {
+ return E_FAIL;
+ }
+
+ const DWORD dRetryInterval = 100;
+ const int iMaxRetries = 25;
+
+ for(int i = 0; i < iMaxRetries; ++i)
+ {
+ HANDLE hMutex = CreateMutex(NULL, FALSE, pszClass);
+
+ DWORD dw = GetLastError();
+
+ if(NULL == hMutex)
+ {
+ HRESULT hr;
+
+ switch(dw)
+ {
+ case ERROR_INVALID_HANDLE:
+ // A non-mutext object with this name already exists.
+ hr = E_INVALIDARG;
+ break;
+ default:
+ // This should never happen...
+ hr = E_FAIL;
+ }
+
+ return hr;
+ }
+
+ // If the mutex already exists, then there should be another instance running
+ if(dw == ERROR_ALREADY_EXISTS)
+ {
+ CloseHandle(hMutex);
+
+ HWND hwnd = NULL;
+ if (bDialog)
+ hwnd = FindWindow(NULL, pszClass);
+ else
+ hwnd = FindWindow(pszClass, NULL);
+
+ if(hwnd == NULL)
+ {
+ Sleep(dRetryInterval);
+ continue;
+ }
+ else
+ {
+ // Transmit our params to previous instance
+ if (lpstrCmdLine && *lpstrCmdLine)
+ {
+ COPYDATASTRUCT cd = { NULL, sizeof(TCHAR) * (wcslen(lpstrCmdLine) + 1), (PVOID)lpstrCmdLine };
+ ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cd);
+ }
+ // Set the previous instance as the foreground window
+ if(0 != SetForegroundWindow(reinterpret_cast<HWND>(reinterpret_cast<ULONG>(hwnd) | 0x1)))
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ return S_OK;
+ }
+ }
+ return S_OK;
+ }
+
+// Operations overriden in derived class
+ bool AppHibernate(bool /*bHibernate*/)
+ {
+ return false;
+ }
+
+ bool AppNewInstance(LPCTSTR /*lpstrCmdLine*/)
+ {
+ return false;
+ }
+
+ void AppSave()
+ {
+ }
+
+#ifdef WIN32_PLATFORM_WFSP
+ void AppBackKey()
+ {
+ ::SHNavigateBack();
+ }
+#endif
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CAppWindowBase)
+ MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
+#ifdef WIN32_PLATFORM_WFSP
+ MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
+#else
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+#endif // WIN32_PLATFORM_WFSP
+ MESSAGE_HANDLER(WM_HIBERNATE, OnHibernate)
+ MESSAGE_HANDLER(WM_COPYDATA, OnNewInstance)
+ MESSAGE_HANDLER(WM_CLOSE, OnClose)
+ END_MSG_MAP()
+
+ LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ if (m_bHibernate)
+ m_bHibernate = pT->AppHibernate(false);
+#ifndef WIN32_PLATFORM_WFSP
+ ::SHHandleWMActivate(pT->m_hWnd, wParam, lParam, &m_sai, 0);
+#else
+ wParam;
+ lParam;
+#endif // WIN32_PLATFORM_WFSP
+ return bHandled = FALSE;
+ }
+
+#ifdef WIN32_PLATFORM_WFSP
+// SmartPhone VK_TBACK key standard management
+ LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ const UINT uModif = (UINT)LOWORD(lParam);
+ const UINT uVirtKey = (UINT)HIWORD(lParam);
+ if(uVirtKey == VK_TBACK)
+ if (AtlIsEditFocus())
+ ::SHSendBackToFocusWindow(uMsg, wParam, lParam);
+ else if (uModif & MOD_KEYUP)
+ pT->AppBackKey();
+ return 1;
+ }
+
+#else // !WIN32_PLATFORM_WFSP
+// PPC SIP handling
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ bHandled = FALSE;
+ return ::SHHandleWMSettingChange(pT->m_hWnd, wParam, lParam, &m_sai);
+ }
+#endif // !WIN32_PLATFORM_WFSP
+
+ LRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ return m_bHibernate = pT->AppHibernate(true);
+ }
+
+ LRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
+ return pT->AppNewInstance((LPCTSTR)pcds->lpData);
+ }
+
+ LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->AppSave();
+ bHandled = FALSE;
+ return 1;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppWindow - PPC/SmartPhone "well-behaved" application window class
+
+template <class T>
+class CAppWindow : public CAppWindowBase< T >
+{
+public:
+ // Same as WTL 7.1 AppWizard generated Run + lpstrCmdLine in CreateEx
+ static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL)
+ {
+ CMessageLoop theLoop;
+ _Module.AddMessageLoop(&theLoop);
+
+ T wndMain;
+
+ if(wndMain.CreateEx(NULL, NULL, 0, 0, lpstrCmdLine) == NULL)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Main window creation failed!\n"));
+ return 0;
+ }
+
+ wndMain.ShowWindow(nCmdShow);
+
+ int nRet = theLoop.Run();
+
+ _Module.RemoveMessageLoop();
+ return nRet;
+ }
+
+ static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine)
+ {
+ return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, false);
+ }
+};
+
+
+#ifndef _WTL_CE_NO_DIALOGS
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppDialog - PPC/SmartPhone "well-behaved" dialog application class
+
+// Macro for declaring dialog WNDCLASS and AppKey
+#define DECLARE_APP_DLG_CLASS(WndClassName, uCommonResourceID, uAppKey) \
+ static WTL::CFrameWndClassInfo& GetWndClassInfo() \
+ { \
+ static WTL::CFrameWndClassInfo wc = \
+ { \
+ { 0, (WNDPROC)StartDialogProc, \
+ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
+ }; \
+ return wc; \
+ }; \
+ DECLARE_APPKEY(uAppKey)
+
+template <class T>
+class CAppDialog : public CAppWindowBase< T >
+{
+public:
+ static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL)
+ {
+ CMessageLoop theLoop;
+ _Module.AddMessageLoop(&theLoop);
+
+ T dlgMain;
+
+ if(dlgMain.Create(NULL, (LPARAM)lpstrCmdLine) == NULL)
+ {
+ ATLTRACE2(atlTraceUI, 0, _T("Main dialog creation failed!\n"));
+ return 0;
+ }
+
+ dlgMain.ShowWindow(nCmdShow);
+
+ int nRet = theLoop.Run();
+
+ _Module.RemoveMessageLoop();
+ return nRet;
+ }
+
+ static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine)
+ {
+ return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, true);
+ };
+};
+
+// PPC/SmartPhone standard application dialogs
+
+#ifdef WIN32_PLATFORM_WFSP
+#define WTL_APP_SHIDIF WTL_SP_SHIDIF
+#else
+#define WTL_APP_SHIDIF WTL_STD_SHIDIF
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdDialogImplBase - Base implementation of standard application dialogs
+
+template <class T, class TImplBase, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdDialogImplBase :
+ public TImplBase,
+ public CAppDialog< T >
+{
+public:
+ WTL_DLG_NOTITLE;
+
+ void StdCloseDialog(int nVal)
+ {
+ T* pT = static_cast<T*>(this);
+ if (nVal != IDCANCEL)
+ pT->AppSave();
+ if (t_bModal == false)
+ {
+ pT->DestroyWindow();
+ ::PostQuitMessage(nVal);
+ }
+ else
+ ::EndDialog(pT->m_hWnd, nVal);
+ }
+
+ BEGIN_MSG_MAP(CAppStdDialogImplBase)
+ MESSAGE_HANDLER(WM_CLOSE, OnSystemClose)
+ CHAIN_MSG_MAP(TImplBase)
+ CHAIN_MSG_MAP(CAppDialog< T >)
+ END_MSG_MAP()
+
+ LRESULT OnSystemClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
+ {
+ T* pT = static_cast<T*>(this);
+ pT->StdCloseDialog(IDCANCEL);
+ return 0;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdDialogImpl - Implementation of standard application dialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdDialogImpl :
+ public CAppStdDialogImplBase<T, CStdDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdDialogResizeImpl :
+ public CAppStdDialogImplBase<T, CStdDialogResizeImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+
+#ifndef _ATL_NO_HOSTING
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdAxDialogImpl - Implementation of standard application AxDialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdAxDialogImpl :
+ public CAppStdDialogImplBase<T, CStdAxDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdAxDialogResizeImpl :
+ public CAppStdDialogImplBase<T, CStdAxDialogResizeImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+#endif // _ATL_NO_HOSTING
+
+#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdOrientedDialogImpl :
+ public CAppStdDialogImplBase<T, CStdOrientedDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+
+#ifndef _ATL_NO_HOSTING
+///////////////////////////////////////////////////////////////////////////////
+// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog
+
+template <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>
+class ATL_NO_VTABLE CAppStdAxOrientedDialogImpl :
+ public CAppStdDialogImplBase<T, CStdAxOrientedDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>
+{};
+#endif // _ATL_NO_HOSTING
+
+#endif // defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)
+
+#endif // _WTL_CE_NO_DIALOGS
+
+#endif // _WTL_CE_NO_APPWINDOW
+
+
+// --- Full screen support ---
+
+#ifndef _WTL_CE_NO_FULLSCREEN
+
+///////////////////////////////////////////////////////////////////////////////
+// CFullScreenFrame - full screen frame implementation
+
+template <class T, bool t_bHasSip = true>
+class CFullScreenFrame
+{
+public:
+ bool m_bFullScreen;
+
+ CFullScreenFrame() : m_bFullScreen(false)
+ { }
+
+// Operation
+ void SetFullScreen(bool bFull)
+ {
+ m_bFullScreen = bFull;
+ ShowTaskBar(!bFull, false);
+ ShowMenuBar(!bFull);
+ }
+
+// Manage TaskBar for modal dialogs and property sheets
+ template <class D>
+ int FSDoModal(D& dlg)
+ {
+ T* pT = static_cast<T*>(this);
+ pT; // avoid level 4 warning
+ ATLASSERT(pT->IsWindow());
+ if (m_bFullScreen) // Show taskbar if hidden
+ ShowTaskBar(true, false);
+ int iRet = dlg.DoModal();
+ if (m_bFullScreen) // Hide taskbar if restored
+ ShowTaskBar(false);
+ return iRet;
+ }
+
+// Implementation
+ void ShowMenuBar(bool bShow)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ ATL::CWindow MenuBar = pT->m_hWndCECommandBar;
+ ATLASSERT(MenuBar.IsWindow());
+ MenuBar.ShowWindow(bShow ? SW_SHOWNORMAL : SW_HIDE);
+ pT->SizeToMenuBar();
+ }
+
+ void ShowTaskBar(bool bShow, bool bRepaint = true)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(pT->IsWindow());
+ RECT rect = { 0 };
+ SystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, FALSE);
+ if (!bShow)
+ rect.top = 0;
+
+#ifdef WIN32_PLATFORM_PSPC // Pocket PC code
+ UINT uShow = t_bHasSip ? SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON : SHFS_SHOWTASKBAR | SHFS_HIDESIPBUTTON;
+ SHFullScreen(pT->m_hWnd, bShow ? uShow : SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON);
+#elif _WIN32_WCE > 0x500 // Smartphone 2005 code
+ SHFullScreen(pT->m_hWnd, bShow ? SHFS_SHOWTASKBAR : SHFS_HIDETASKBAR);
+#else // Smartphone 2003
+ HWND hTaskBar = FindWindow(_T("tray"), NULL);
+ ATLASSERT(::IsWindow(hTaskBar));
+ ::ShowWindow(hTaskBar, bShow ? SW_SHOW : SW_HIDE);
+#endif // WIN32_PLATFORM_PSPC
+
+ pT->MoveWindow(&rect, bRepaint);
+ }
+
+// Message map and handler
+ BEGIN_MSG_MAP(CFullScreenFrame)
+ MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
+ MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
+ END_MSG_MAP()
+
+ LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+#ifndef SETTINGCHANGE_RESET // not defined for PPC 2002
+ #define SETTINGCHANGE_RESET SPI_SETWORKAREA
+#endif
+ if (m_bFullScreen && (wParam == SETTINGCHANGE_RESET))
+ SetFullScreen(m_bFullScreen);
+ return bHandled = FALSE;
+ }
+
+ LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ if (m_bFullScreen)
+ {
+ ShowTaskBar(!wParam);
+ ShowMenuBar(!wParam);
+ }
+ return bHandled = FALSE;
+ }
+};
+
+#endif // _WTL_CE_NO_FULLSCREEN
+
+
+// --- WinCE zoom support ---
+
+#ifndef _WTL_CE_NO_ZOOMSCROLL
+
+///////////////////////////////////////////////////////////////////////////////
+// CZoomScrollImpl - WinCE zooming implementation on top of CScrollImpl
+
+template <class T>
+class CZoomScrollImpl: public CScrollImpl< T >
+{
+public:
+// Data members
+ _WTYPES_NS::CSize m_sizeTrue;
+ double m_fzoom;
+
+// Creation
+ CZoomScrollImpl() : m_sizeTrue(0), m_fzoom(1.)
+ { }
+
+// Zoom operations and access
+ void SetZoomScrollSize(_WTYPES_NS::CSize sizeTrue, double fzoom = 1., BOOL bRedraw = TRUE)
+ {
+ ATLASSERT(fzoom > 0.);
+ m_sizeTrue = sizeTrue;
+ m_fzoom = fzoom;
+
+ CScrollImpl< T >::SetScrollSize(sizeTrue / fzoom, bRedraw);
+ }
+
+ void SetZoomScrollSize(int cx, int cy, double fzoom=1., BOOL bRedraw = TRUE)
+ {
+ SetZoomScrollSize(_WTYPES_NS::CSize(cx, cy), fzoom, bRedraw);
+ }
+
+ void SetZoom(double fzoom, BOOL bRedraw = TRUE)
+ {
+ _WTYPES_NS::CPoint ptCenter = WndtoTrue(m_sizeClient / 2);
+ _WTYPES_NS::CSize sizePage = GetScrollPage();
+ _WTYPES_NS::CSize sizeLine = GetScrollLine();
+
+ SetZoomScrollSize(GetScrollSize(), fzoom, bRedraw);
+
+ SetScrollLine(sizeLine);
+ SetScrollPage(sizePage);
+ _WTYPES_NS::CPoint ptOffset = ptCenter - (m_sizeClient / 2) * fzoom;
+ SetScrollOffset(ptOffset, bRedraw);
+ }
+
+ double GetZoom()
+ {
+ return m_fzoom;
+ }
+
+// CScrollImpl overrides
+ void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)
+ {
+ CScrollImpl< T >::SetScrollOffset((int)(x / m_fzoom), (int)(y / m_fzoom), bRedraw);
+ }
+
+ void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)
+ {
+ SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);
+ }
+
+ void GetScrollOffset(POINT& ptOffset)
+ {
+ ptOffset.x = (LONG)(m_ptOffset.x * m_fzoom);
+ ptOffset.y = (LONG)(m_ptOffset.y * m_fzoom);
+ }
+
+ void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE)
+ {
+ SetZoomScrollSize(cx, cy, GetZoom(), bRedraw);
+ }
+
+ void SetScrollSize(SIZE sizeTrue, BOOL bRedraw = TRUE)
+ {
+ SetZoomScrollSize(sizeTrue, GetZoom(), bRedraw);
+ }
+
+ void GetScrollSize(SIZE& sizeTrue) const
+ {
+ sizeTrue = m_sizeTrue;
+ }
+
+ void SetScrollPage(int cxPage, int cyPage)
+ {
+ SetScrollPage(_WTYPES_NS::CSize(cxPage, cyPage));
+ }
+
+ void SetScrollPage(SIZE sizePage)
+ {
+ CScrollImpl< T >::SetScrollPage(sizePage / m_fzoom);
+ }
+
+ void GetScrollPage(SIZE& sizePage) const
+ {
+ sizePage = m_sizePage * m_fzoom;
+ }
+
+ void SetScrollLine(int cxLine, int cyLine)
+ {
+ SetScrollLine(_WTYPES_NS::CSize(cxLine, cyLine));
+ }
+
+ void SetScrollLine(SIZE sizeLine)
+ {
+ CScrollImpl< T >::SetScrollLine(sizeLine / m_fzoom);
+ }
+
+ void GetScrollLine(SIZE& sizeLine) const
+ {
+ sizeLine = m_sizeLine * m_fzoom;
+ }
+
+// Data access complements
+ _WTYPES_NS::CSize GetScrollSize()
+ {
+ return m_sizeTrue;
+ }
+
+ _WTYPES_NS::CSize GetScrollPage()
+ {
+ return m_sizePage * m_fzoom;
+ }
+
+ _WTYPES_NS::CSize GetScrollLine()
+ {
+ return m_sizeLine * m_fzoom;
+ }
+
+ _WTYPES_NS::CPoint GetScrollOffset()
+ {
+ return (_WTYPES_NS::CSize)m_ptOffset * m_fzoom;
+ }
+
+// Helper coordinate functions
+ _WTYPES_NS::CPoint WndtoTrue(CPoint ptW)
+ {
+ return (_WTYPES_NS::CSize)ptW * GetZoom() + GetScrollOffset();
+ }
+
+ void WndtoTrue(LPPOINT aptW, int nPts) // in place coord transformation
+ {
+ for (int i = 0 ; i < nPts ; i++)
+ aptW[i] = WndtoTrue(aptW[i]);
+ }
+
+ void WndtoTrue(LPRECT prectW) // in place coord transformation
+ {
+ WndtoTrue((LPPOINT)prectW, 2);
+ }
+
+ _WTYPES_NS::CPoint TruetoWnd(CPoint ptT)
+ {
+ return (ptT - GetScrollOffset()) / GetZoom();
+ }
+
+ void TruetoWnd(LPPOINT aptT, int nPts) // in place coord transformation
+ {
+ for (int i = 0 ; i < nPts ; i++)
+ aptT[i] = TruetoWnd(aptT[i]);
+ }
+
+ void TruetoWnd(LPRECT prectT) // in place coord transformation
+ {
+ TruetoWnd((LPPOINT)prectT, 2);
+ }
+
+// Drawing operations : assume adequate setting of data members
+ BOOL Draw(HBITMAP hbm, HDC hdestDC, DWORD dwROP = SRCCOPY)
+ {
+ CDC memDC = CreateCompatibleDC(hdestDC);
+ CBitmapHandle bmpOld = memDC.SelectBitmap(hbm);
+ BOOL bRes = Draw(memDC, hdestDC, dwROP);
+ memDC.SelectBitmap(bmpOld);
+ return bRes;
+ }
+
+ BOOL Draw(HDC hsourceDC, HDC hdestDC, DWORD dwROP = SRCCOPY)
+ {
+ CDCHandle destDC = hdestDC;
+ destDC.SetViewportOrg(0,0);
+ _WTYPES_NS::CPoint ptOffset = GetScrollOffset();
+ _WTYPES_NS::CSize sizeZClient = m_sizeClient * GetZoom();
+ return destDC.StretchBlt(0, 0, m_sizeClient.cx, m_sizeClient.cy, hsourceDC, ptOffset.x, ptOffset.y, sizeZClient.cx, sizeZClient.cy, dwROP);
+ }
+
+#ifdef _IMAGING_H
+ BOOL Draw(IImage* pIImage, HDC hdestDC)
+ {
+ CDCHandle destDC = hdestDC;
+ destDC.SetViewportOrg(0,0);
+ return SUCCEEDED(pIImage->Draw(destDC, _WTYPES_NS::CRect(-_WTYPES_NS::CPoint(m_ptOffset), m_sizeAll), NULL));
+ }
+#endif
+
+// Message map and handlers
+ BEGIN_MSG_MAP(CZoomScrollImpl< T >)
+ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
+ CHAIN_MSG_MAP(CScrollImpl< T >)
+ END_MSG_MAP()
+
+ LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
+ {
+ T* pT = static_cast<T*>(this);
+ ATLASSERT(::IsWindow(pT->m_hWnd));
+ if ((GetScrollExtendedStyle() & SCRL_ERASEBACKGROUND))
+ {
+ _WTYPES_NS::CRect rect;
+ pT->GetClientRect(rect);
+ _WTYPES_NS::CSize sizeClient=rect.Size();
+
+ if (m_sizeAll.cx < sizeClient.cx || m_sizeAll.cy < sizeClient.cy)
+ {
+ CDCHandle hdc = (HDC)wParam;
+ HBRUSH hbr = GetSysColorBrush((int)T::GetWndClassInfo().m_wc.hbrBackground - 1);
+
+ if (m_sizeAll.cx < sizeClient.cx)
+ {
+ _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(m_sizeAll.cx, 0), sizeClient);
+ hdc.FillRect(rectBG, hbr);
+ }
+
+ if (m_sizeAll.cy < sizeClient.cy)
+ {
+ _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(0, m_sizeAll.cy), sizeClient);
+ hdc.FillRect(rectBG, hbr);
+ }
+ }
+ }
+ else
+ {
+ bHandled = FALSE;
+ }
+
+ return 1;
+ }
+};
+
+#endif // _WTL_CE_NO_ZOOMSCROLL
+
+#ifndef _WTL_CE_NO_CONTROLS
+
+// --- PPC bottom TabView control ---
+
+#if defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC)
+
+///////////////////////////////////////////////////////////////////////////////
+// CBottomTabViewImpl
+
+template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
+class ATL_NO_VTABLE CBottomTabViewImpl : public CTabViewImpl<T, TBase, TWinTraits>
+{
+public:
+ DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE)
+
+// Implementation overrideables
+ bool CreateTabControl()
+ {
+ m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | TCS_BOTTOM, 0, m_nTabID);
+
+ ATLASSERT(m_tab.m_hWnd != NULL);
+ if(m_tab.m_hWnd == NULL)
+ return false;
+
+ m_tab.SendMessage(CCM_SETVERSION, COMCTL32_VERSION);
+ m_tab.SetItemExtra(sizeof(TABVIEWPAGE));
+
+ T* pT = static_cast<T*>(this);
+ m_cyTabHeight = pT->CalcTabHeight();
+
+ return true;
+ }
+
+ int CalcTabHeight()
+ {
+ int nCount = m_tab.GetItemCount();
+ TCITEMEXTRA tcix = { 0 };
+ tcix.tciheader.mask = TCIF_TEXT;
+ tcix.tciheader.pszText = _T("NS");
+ int nIndex = m_tab.InsertItem(nCount, tcix);
+
+ RECT rect = { 0 };
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
+ RECT rcWnd = rect;
+
+ m_tab.AdjustRect(FALSE, &rect);
+ rcWnd.top = rect.bottom;
+ ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle());
+ m_tab.DeleteItem(nIndex);
+
+ return rcWnd.bottom - rcWnd.top;
+ }
+
+ void UpdateLayout()
+ {
+ RECT rect;
+ GetClientRect(&rect);
+
+ if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
+ m_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER /*| SWP_SHOWWINDOW*/);
+
+ if(m_nActivePage != -1)
+ ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - m_cyTabHeight, SWP_NOZORDER);
+ }
+
+};
+
+class CBottomTabView : public CBottomTabViewImpl<CBottomTabView>
+{
+public:
+ DECLARE_WND_CLASS_EX(_T("WTL_BottomTabView"), 0, COLOR_APPWORKSPACE)
+};
+
+#endif // defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC)
+
+
+// --- PPC/SmartPhone controls ---
+
+////////////////////////////////////////////////////////////////////////////////
+// These are wrapper classes for the Pocket PC 2002/2003 and SmartPhone 2003 controls
+// To implement a window based on a control, use following:
+// Example: Implementing a window based on a Html control
+//
+// class CMyHtml : CWindowImpl<CMyHtml, CHtmlCtrl>
+// {
+// public:
+// BEGIN_MSG_MAP(CMyHtml)
+// // put your message handler entries here
+// END_MSG_MAP()
+// };
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// CHtmlCtrl
+
+template <class TBase>
+class CHtmlCtrlT : public TBase
+{
+public:
+// Constructors
+ CHtmlCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CHtmlCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call InitHTMLControl(hInstance) ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_HTML;
+ }
+
+#if (_WIN32_WCE >= 400)
+ void AddStyle(LPCWSTR pszStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ADDSTYLE, 0, (LPARAM)pszStyle);
+ }
+#endif // (_WIN32_WCE >= 400)
+
+ void AddText(BOOL bPlainText, LPCSTR pszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)bPlainText, (LPARAM)pszText);
+ }
+
+ void AddHTML(LPCSTR pszHTML)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)FALSE, (LPARAM)pszHTML);
+ }
+
+ void AddText(BOOL bPlainText, LPCWSTR pszText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)bPlainText, (LPARAM)pszText);
+ }
+
+ void AddHTML(LPCWSTR pszHTML)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)FALSE, (LPARAM)pszHTML);
+ }
+
+ void Anchor(LPCSTR pszAnchor)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ANCHOR, 0, (LPARAM)pszAnchor);
+ }
+
+ void Anchor(LPCWSTR pszAnchor)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ANCHORW, 0, (LPARAM)pszAnchor);
+ }
+
+#if (_WIN32_WCE >= 420)
+ void GetBrowserDispatch(IDispatch** ppDispatch)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(ppDispatch);
+ ATLASSERT(*ppDispatch==NULL);
+ ::SendMessage(m_hWnd, DTM_BROWSERDISPATCH, 0, (LPARAM)ppDispatch);
+ }
+ void GetDocumentDispatch(IDispatch** ppDispatch)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(ppDispatch);
+ ATLASSERT(*ppDispatch==NULL);
+ ::SendMessage(m_hWnd, DTM_DOCUMENTDISPATCH , 0, (LPARAM)ppDispatch);
+ }
+#endif // (_WIN32_WCE >= 420)
+
+ void Clear()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_CLEAR, 0, 0L);
+ }
+
+ void EnableClearType(BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ENABLECLEARTYPE, 0, (LPARAM)bEnable);
+ }
+
+ void EnableContextMenu(BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ENABLECONTEXTMENU, 0, (LPARAM)bEnable);
+ }
+
+ void EnableScripting(BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ENABLESCRIPTING, 0, (LPARAM)bEnable);
+ }
+
+ void EnableShrink(BOOL bEnable = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ENABLESHRINK, 0, (LPARAM)bEnable);
+ }
+
+ void EndOfSource()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ENDOFSOURCE, 0, 0L);
+ }
+
+ void ImageFail(DWORD dwCookie)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_IMAGEFAIL, 0, (LPARAM)dwCookie);
+ }
+
+ int GetLayoutHeight() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DTM_LAYOUTHEIGHT, 0, 0L);
+ }
+
+ int GetLayoutWidth() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DTM_LAYOUTWIDTH, 0, 0L);
+ }
+
+ void Navigate(LPCTSTR pstrURL, UINT uFlags = 0)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrURL);
+ ::SendMessage(m_hWnd, DTM_NAVIGATE, (WPARAM)uFlags, (LPARAM)pstrURL);
+ }
+
+ void SelectAll()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_SELECTALL, 0, 0L);
+ }
+
+ void SetImage(INLINEIMAGEINFO* pImageInfo)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pImageInfo);
+ ::SendMessage(m_hWnd, DTM_SETIMAGE, 0, (LPARAM)pImageInfo);
+ }
+
+ void ZoomLevel(int iLevel)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_ZOOMLEVEL, 0, (LPARAM)iLevel);
+ }
+
+#if (_WIN32_WCE >= 400)
+ void Stop()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DTM_STOP, 0, 0L);
+ }
+#endif // (_WIN32_WCE >= 400)
+
+ void GetScriptDispatch(IDispatch** ppDispatch)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(ppDispatch);
+ ATLASSERT(*ppDispatch==NULL);
+ ::SendMessage(m_hWnd, DTM_SCRIPTDISPATCH, 0, (LPARAM)ppDispatch);
+ }
+};
+
+typedef CHtmlCtrlT<ATL::CWindow> CHtmlCtrl;
+
+
+#ifdef WIN32_PLATFORM_PSPC
+
+///////////////////////////////////////////////////////////////////////////////
+// CRichInkCtrl
+
+template <class TBase>
+class CRichInkCtrlT : public TBase
+{
+public:
+// Constructors
+ CRichInkCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CRichInkCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call InitRichInkDLL() ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_RICHINK;
+ }
+
+ BOOL CanPaste(UINT uFormat = 0) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, (WPARAM)uFormat, 0L);
+ }
+
+ BOOL CanRedo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L);
+ }
+
+ BOOL CanUndo() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);
+ }
+
+ void ClearAll(BOOL bRepaint = TRUE) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_CLEARALL, (WPARAM)bRepaint, 0L);
+ }
+
+ BOOL GetModify() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);
+ }
+
+ UINT GetPageStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETPAGESTYLE, 0, 0L);
+ }
+
+ UINT GetPenMode() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETPENMODE, 0, 0L);
+ }
+
+ UINT GetViewStyle() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETVIEW, 0, 0L);
+ }
+
+ UINT GetWrapMode() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETWRAPMODE, 0, 0L);
+ }
+
+ UINT GetZoomPercent() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_GETZOOMPERCENT, 0, 0L);
+ }
+
+ void InsertLinks(LPWSTR lpString, int cchLength = -1)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ if(cchLength == -1)
+ cchLength = lstrlen(lpString);
+ ::SendMessage(m_hWnd, EM_INSERTLINKS, (WPARAM)cchLength, (LPARAM)lpString);
+ }
+
+ void RedoEvent()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_REDOEVENT, 0, 0L);
+ }
+
+ UINT SetInkLayer(UINT uLayer)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (UINT)::SendMessage(m_hWnd, EM_SETINKLAYER, (WPARAM)uLayer, 0L);
+ }
+
+ void SetPageStyle(UINT uStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETPAGESTYLE, (WPARAM)uStyle, 0L);
+ }
+
+ void SetPenMode(UINT uMode)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETPENMODE, (WPARAM)uMode, 0L);
+ }
+
+ void SetViewStyle(UINT uStyle)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETVIEW, (WPARAM)uStyle, 0L);
+ }
+
+ void SetViewAttributes(VIEWATTRIBUTES* pAttribs)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pAttribs);
+ ::SendMessage(m_hWnd, EM_SETVIEWATTRIBUTES, 0, (LPARAM)pAttribs);
+ }
+
+ void SetWrapMode(UINT uMode)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETWRAPMODE, (WPARAM)uMode, 0L);
+ }
+
+ void SetZoomPercent(UINT uPercent)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETZOOMPERCENT, (WPARAM)uPercent, 0L);
+ }
+
+ LONG StreamIn(UINT uFormat, EDITSTREAM& es)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, (WPARAM)uFormat, (LPARAM)&es);
+ }
+
+ LONG StreamOut(UINT uFormat, EDITSTREAM& es)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, (WPARAM)uFormat, (LPARAM)&es);
+ }
+
+ void UndoEvent()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_UNDOEVENT, 0, 0L);
+ }
+
+ void Undo()
+ {
+ UndoEvent();
+ }
+
+// Standard EM_xxx messages
+ DWORD GetSel() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);
+ return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L);
+ }
+
+ void GetSel(int& nStartChar, int& nEndChar) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);
+ ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
+ }
+
+ void SetSel(int nStartChar, int nEndChar)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);
+ ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar);
+ }
+
+ void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);
+ ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM)bCanUndo, (LPARAM)lpszNewText);
+ }
+
+ void SetModify(BOOL bModified = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, EM_SETMODIFY, (WPARAM)bModified, 0L);
+ }
+
+ int GetTextLength() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L);
+ }
+
+// Clipboard operations
+ void Clear()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);
+ }
+
+ void Copy()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_COPY, 0, 0L);
+ }
+
+ void Cut()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_CUT, 0, 0L);
+ }
+
+ void Paste()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, WM_PASTE, 0, 0L);
+ }
+};
+
+typedef CRichInkCtrlT<ATL::CWindow> CRichInkCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CInkXCtrl
+
+template <class TBase>
+class CInkXCtrlT : public TBase
+{
+public:
+// Constructors
+ CInkXCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CInkXCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call InitInkX() ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_INKX;
+ }
+
+ static UINT GetHotRecordingMessage()
+ {
+ return ::RegisterWindowMessage(szHotRecording);
+ }
+
+ void ClearAll()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IM_CLEARALL, 0, 0L);
+ }
+
+ int GetData(BYTE* lpBuffer, INT cbBuffer) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpBuffer);
+ return (int)::SendMessage(m_hWnd, IM_GETDATA, (WPARAM)cbBuffer, (LPARAM)lpBuffer);
+ }
+
+ int GetDataLen() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, IM_GETDATALEN, 0, 0L);
+ }
+
+ CRichInkCtrl GetRichInk() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HWND)::SendMessage(m_hWnd, IM_GETRICHINK, 0, 0L);
+ }
+
+ BOOL IsRecording() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, IM_RECORDING, 0, 0L);
+ }
+
+ void ReInit()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IM_REINIT, 0, 0L);
+ }
+
+ void SetData(const BYTE* lpInkData, INT cbInkData)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(lpInkData);
+ ::SendMessage(m_hWnd, IM_SETDATA, (WPARAM)cbInkData, (LPARAM)lpInkData);
+ }
+
+ void VoicePlay()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IM_VOICE_PLAY, 0, 0L);
+ }
+
+ BOOL IsVoicePlaying() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, IM_VOICE_PLAYING, 0, 0L);
+ }
+
+ BOOL VoiceRecord()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, IM_VOICE_RECORD, 0, 0L);
+ }
+
+ void VoiceStop()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IM_VOICE_STOP, 0, 0L);
+ }
+
+ void ShowVoiceBar(BOOL bShow = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, IM_VOICEBAR, (WPARAM)bShow, 0L);
+ }
+};
+
+typedef CInkXCtrlT<ATL::CWindow> CInkXCtrl;
+
+#endif // WIN32_PLATFORM_PSPC
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CVoiceRecorderCtrl
+
+template <class TBase>
+class CVoiceRecorderCtrlT : public TBase
+{
+public:
+// Constructors
+ CVoiceRecorderCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CVoiceRecorderCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, const POINT pt, LPTSTR pstrFileName, UINT nID, DWORD dwStyle = 0)
+ {
+ ATLASSERT(pstrFileName != NULL);
+ CM_VOICE_RECORDER cmvr = { 0 };
+ cmvr.cb = sizeof(CM_VOICE_RECORDER);
+ cmvr.dwStyle = dwStyle;
+ cmvr.xPos = pt.x;
+ cmvr.yPos = pt.y;
+ cmvr.hwndParent = hWndParent;
+ cmvr.id = nID;
+ cmvr.lpszRecordFileName = pstrFileName;
+ m_hWnd = VoiceRecorder_Create(&cmvr);
+ return m_hWnd;
+ }
+
+ HWND Create(LPCM_VOICE_RECORDER pAttribs)
+ {
+ ATLASSERT(pAttribs);
+ m_hWnd = VoiceRecorder_Create(pAttribs);
+ return m_hWnd;
+ }
+
+// Attributes
+ void Record()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, VRM_RECORD, 0, 0L);
+ }
+
+ void Play()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, VRM_PLAY, 0, 0L);
+ }
+
+ void Stop()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, VRM_STOP, 0, 0L);
+ }
+
+ void Cancel()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, VRM_CANCEL, 0, 0L);
+ }
+
+ void Done()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, VRM_OK, 0, 0L);
+ }
+};
+
+typedef CVoiceRecorderCtrlT<ATL::CWindow> CVoiceRecorderCtrl;
+
+
+#ifdef WIN32_PLATFORM_PSPC
+
+///////////////////////////////////////////////////////////////////////////////
+// CDocListCtrl
+
+template <class TBase>
+class CDocListCtrlT : public TBase
+{
+public:
+// Attributes
+ DOCLISTCREATE m_dlc;
+ TCHAR m_szPath[MAX_PATH];
+
+// Constructors
+ CDocListCtrlT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CDocListCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, WORD wId, LPCTSTR pszFolder = NULL, LPCTSTR pstrFilter = NULL,
+ WORD wFilterIndex = 0, DWORD dwFlags = DLF_SHOWEXTENSION)
+ {
+ ATLASSERT(pstrFilter != NULL); // It seems to need a filter badly!!
+ ::ZeroMemory(&m_dlc, sizeof(DOCLISTCREATE));
+ ::ZeroMemory(m_szPath, sizeof(m_szPath));
+ if(pszFolder != NULL)
+ SecureHelper::strncpy_x(m_szPath, MAX_PATH, pszFolder, MAX_PATH - 1);
+ m_dlc.dwStructSize = sizeof(DOCLISTCREATE);
+ m_dlc.hwndParent = hWndParent;
+ m_dlc.pszFolder = m_szPath;
+ m_dlc.pstrFilter = pstrFilter;
+ m_dlc.wFilterIndex = wFilterIndex;
+ m_dlc.wId = wId;
+ m_dlc.dwFlags = dwFlags;
+ m_hWnd = DocList_Create(&m_dlc);
+ return m_hWnd;
+ }
+
+ HWND Create(DOCLISTCREATE* pDlc)
+ {
+ m_dlc = *pDlc;
+ m_hWnd = DocList_Create(&m_dlc);
+ return m_hWnd;
+ }
+
+// Attributes
+ void DeleteSel()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_DELETESEL, 0, 0L);
+ }
+
+ void DisableUpdates()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_DISABLEUPDATES, 0, 0L);
+ }
+
+ void EnableUpdates()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_ENABLEUPDATES, 0, 0L);
+ }
+
+ int GetFilterIndex() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_GETFILTERINDEX, 0, 0L);
+ }
+
+ int GetItemCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_GETITEMCOUNT, 0, 0L);
+ }
+
+ int GetNextItem(int iIndex, DWORD dwRelation = LVNI_ALL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)dwRelation);
+ }
+
+ int GetFirstItem(DWORD dwRelation = LVNI_ALL) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)-1, (LPARAM)dwRelation);
+ }
+
+ BOOL GetNextWave(int* pIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pIndex);
+ return (BOOL)::SendMessage(m_hWnd, DLM_GETNEXTWAVE, 0, (LPARAM)pIndex);
+ }
+
+ BOOL GetPrevWave(int* pIndex) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pIndex);
+ return (BOOL)::SendMessage(m_hWnd, DLM_GETPREVWAVE, 0, (LPARAM)pIndex);
+ }
+
+ int GetSelCount() const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_GETSELCOUNT, 0, 0L);
+ }
+
+ BOOL GetSelPathName(LPTSTR pstrPath, int cchMax) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrPath);
+ return (BOOL)::SendMessage(m_hWnd, DLM_GETSELPATHNAME, (WPARAM)cchMax, (LPARAM)pstrPath);
+ }
+
+ void ReceiveIR(LPCTSTR pstrPath) const
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrPath);
+ ::SendMessage(m_hWnd, DLM_RECEIVEIR, 0, (LPARAM)pstrPath);
+ }
+
+ void Refresh()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_REFRESH, 0, 0L);
+ }
+
+ BOOL RenameMoveSelectedItems()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DLM_RENAMEMOVE, 0, 0L);
+ }
+
+ int SelectAll()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (int)::SendMessage(m_hWnd, DLM_SELECTALL, 0, 0L);
+ }
+
+ HRESULT SelectItem(LPCTSTR pstrPath, BOOL bVisible = TRUE)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrPath);
+ return (HRESULT)::SendMessage(m_hWnd, DLM_SELECTITEM, (WPARAM)bVisible, (LPARAM)pstrPath);
+ }
+
+ void SendEMail(LPCTSTR pstrAttachment)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_SENDEMAIL, 0, (LPARAM)pstrAttachment);
+ }
+
+ void SendIR(LPCTSTR pstrPath)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_SENDIR, 0, (LPARAM)pstrPath);
+ }
+
+ HRESULT SetFilterIndex(int iIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HRESULT)::SendMessage(m_hWnd, DLM_SETFILTERINDEX, (WPARAM)iIndex, 0L);
+ }
+
+ void SetFolder(LPCTSTR pstrPath)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrPath);
+ ::SendMessage(m_hWnd, DLM_SETFOLDER, 0, (LPARAM)pstrPath);
+ }
+
+ BOOL SetItemState(int iIndex, const LVITEM* pItem)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pItem);
+ return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)pItem);
+ }
+
+ BOOL SetItemState(int iIndex, UINT uState, UINT uMask)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ LV_ITEM lvi = { 0 };
+ lvi.stateMask = uMask;
+ lvi.state = uState;
+ return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)&lvi);
+ }
+
+ void SetOneItem(int iIndex, LPCVOID pPA)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_SETONEITEM, (WPARAM)iIndex, (LPARAM)pPA);
+ }
+
+ void SetSelect(int iIndex)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ::SendMessage(m_hWnd, DLM_SETSELECT, (WPARAM)iIndex, 0L);
+ }
+
+ void SetSelPathName(LPCTSTR pstrPath)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrPath);
+ ::SendMessage(m_hWnd, DLM_SETSELPATHNAME, 0, (LPARAM)pstrPath);
+ }
+
+ BOOL SetSortOrder()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DLM_SETSORTORDER, 0, 0L);
+ }
+
+ HRESULT Update()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (HRESULT)::SendMessage(m_hWnd, DLM_UPDATE, 0, 0L);
+ }
+
+ BOOL ValidateFolder()
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return (BOOL)::SendMessage(m_hWnd, DLM_VALIDATEFOLDER, 0, 0L);
+ }
+
+// Functions
+ BOOL GetFirstSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return DocList_GetFirstSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath);
+ }
+
+ BOOL GetNextSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ return DocList_GetNextSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath);
+ }
+};
+
+typedef CDocListCtrlT<ATL::CWindow> CDocListCtrl;
+
+#endif // WIN32_PLATFORM_PSPC
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CCapEdit
+
+template <class TBase>
+class CCapEditT : public TBase
+{
+public:
+// Constructors
+ CCapEditT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CCapEditT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = /*TBase*/CWindow::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_CAPEDIT;
+ }
+};
+
+typedef CCapEditT<WTL::CEdit> CCapEdit;
+
+///////////////////////////////////////////////////////////////////////////////
+// CTTStatic
+
+#ifndef WIN32_PLATFORM_WFSP // Tooltips not supported on SmartPhone
+
+template <class TBase>
+class CTTStaticT : public TBase
+{
+public:
+// Constructors
+ CTTStaticT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CTTStaticT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_TSTATIC;
+ }
+
+// Operations
+ BOOL SetToolTipText(LPCTSTR pstrTipText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrTipText);
+ ATLASSERT(lstrlen(pstrTipText) <= 253);
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ int cchLen = lstrlen(pstrTipText) + 3;
+ LPTSTR pstr = buff.Allocate(cchLen);
+ if(pstr == NULL)
+ return FALSE;
+ SecureHelper::strcpy_x(pstr, cchLen, _T("~~"));
+ SecureHelper::strcat_x(pstr, cchLen, pstrTipText);
+ return SetWindowText(pstr);
+ }
+};
+
+typedef CTTStaticT<WTL::CStatic> CTTStatic;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CTTButton
+
+template <class TBase>
+class CTTButtonT : public TBase
+{
+public:
+// Constructors
+ CTTButtonT(HWND hWnd = NULL) : TBase(hWnd)
+ { }
+
+ CTTButtonT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+ HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
+ ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ??
+ return hWnd;
+ }
+
+// Attributes
+ static LPCTSTR GetWndClassName()
+ {
+ return WC_TBUTTON;
+ }
+
+// Operations
+ BOOL SetToolTipText(LPCTSTR pstrTipText)
+ {
+ ATLASSERT(::IsWindow(m_hWnd));
+ ATLASSERT(pstrTipText);
+ ATLASSERT(lstrlen(pstrTipText) <= 253);
+ CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
+ int cchLen = lstrlen(pstrTipText) + 3;
+ LPTSTR pstr = buff.Allocate(cchLen);
+ if(pstr == NULL)
+ return FALSE;
+ SecureHelper::strcpy_x(pstr, cchLen, _T("~~"));
+ SecureHelper::strcat_x(pstr, cchLen, pstrTipText);
+ return SetWindowText(pstr);
+ }
+};
+
+typedef CTTButtonT<WTL::CButton> CTTButton;
+
+#endif // !WIN32_PLATFORM_WFSP
+
+
+// --- SmartPhone specific controls ---
+
+#ifdef WIN32_PLATFORM_WFSP
+
+///////////////////////////////////////////////////////////////////////////////
+// CSpinCtrlT - CSpinCtrl : SmartPhone adapted UpDown control
+
+template <class TBase>
+class CSpinCtrlT : public CUpDownCtrlT< TBase >
+{
+public:
+// Constructors
+ CSpinCtrlT(HWND hWnd = NULL) : CUpDownCtrlT< TBase >(hWnd)
+ { }
+
+ CSpinCtrlT< TBase >& operator =(HWND hWnd)
+ {
+ m_hWnd = hWnd;
+ return *this;
+ }
+
+ HWND Create(HWND hWndParent, HWND hBuddy, DWORD dwStyle, int nID, LPCTSTR szExpandedName = NULL)
+ {
+ ATLASSERT(::IsWindow(hWndParent));
+ CUpDownCtrlT< TBase >::Create(hWndParent, NULL, szExpandedName, dwStyle, 0, nID, NULL);
+ ATLASSERT(m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)?
+ if (hBuddy != NULL)
+ {
+ ATLASSERT(::IsWindow(hBuddy));
+ SetBuddy(hBuddy);
+ }
+ return m_hWnd;
+ }
+};
+
+typedef CSpinCtrlT<ATL::CWindow> CSpinCtrl;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSpinned - SmartPhone association of control and Spin
+
+template <class TBase, bool t_bExpandOnly>
+class CSpinned : public TBase
+{
+public:
+ CSpinCtrl m_SpinCtrl;
+ DWORD m_dwSpinnedStyle;
+
+// Constructors
+ CSpinned(HWND hWnd = NULL) : TBase(hWnd)
+ {
+ m_dwSpinnedStyle = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE;
+
+ if (t_bExpandOnly == true)
+ m_dwSpinnedStyle |= UDS_NOSCROLL;
+ else
+ m_dwSpinnedStyle |= UDS_HORZ | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_WRAP;
+
+ if (hWnd != NULL)
+ AttachOrCreateSpinCtrl();
+ }
+
+ CSpinned<TBase, t_bExpandOnly>& operator =(HWND hWnd)
+ {
+ Attach(hWnd);
+ return *this;
+ }
+
+ void Attach(HWND hWnd)
+ {
+ ATLASSERT(!IsWindow());
+ TBase* pT = static_cast<TBase*>(this);
+ pT->m_hWnd = hWnd;
+ if (hWnd != NULL)
+ AttachOrCreateSpinCtrl();
+ }
+
+ HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szExpandedName = NULL,
+ DWORD dwStyle = 0, DWORD dwExStyle = 0,
+ ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
+ {
+
+ TBase* pT = static_cast<TBase*>(this);
+ TBase::Create(hWndParent, rect, NULL, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
+ ATLASSERT(pT->m_hWnd != NULL);
+
+ m_SpinCtrl.Create(hWndParent, pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + (int)MenuOrID.m_hMenu, szExpandedName);
+
+ ATLASSERT(m_SpinCtrl.m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)?
+
+ return pT->m_hWnd;
+ }
+
+// Attributes
+ CSpinCtrl& GetSpinCtrl()
+ {
+ return m_SpinCtrl;
+ }
+
+// Implementation
+ // Attach our existing SpinCtrl or create one
+ bool AttachOrCreateSpinCtrl()
+ {
+ TBase* pT = static_cast<TBase*>(this);
+
+ HWND hSpin = ::GetDlgItem(pT->GetParent(), ATL_IDW_SPIN_ID + pT->GetDlgCtrlID());
+
+ if (hSpin != NULL)
+ {
+ m_SpinCtrl.Attach(hSpin);
+#ifdef DEBUG
+ TCHAR sClassName[16];
+ ::GetClassName(hSpin, sClassName, 16);
+ ATLASSERT(!_tcscmp(sClassName, UPDOWN_CLASS));
+ ATLASSERT(m_SpinCtrl.GetBuddy().m_hWnd == pT->m_hWnd);
+#endif // DEBUG
+ }
+ else
+ {
+ m_SpinCtrl.Create(pT->GetParent(), pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + pT->GetDlgCtrlID());
+ }
+
+ return m_SpinCtrl.m_hWnd != NULL;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSpinListBox - SmartPhone spinned ListBox control
+// CExpandListBox - SmartPhone expandable ListBox control
+// CExpandEdit - SmartPhone expandable Edit control
+// CExpandCapEdit - SmartPhone expandable CapEdit control
+
+typedef CSpinned<CListBox, false> CSpinListBox;
+typedef CSpinned<CListBox, true> CExpandListBox;
+typedef CSpinned<CEdit, true> CExpandEdit;
+typedef CSpinned<CCapEdit, true> CExpandCapEdit;
+
+#endif // WIN32_PLATFORM_WFSP
+
+#endif // _WTL_CE_NO_CONTROLS
+
+}; // namespace WTL
+
+#endif // __ATLWINCE_H__
--- /dev/null
+// Windows Template Library - WTL version 8.1
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// This file is a part of the Windows Template Library.
+// The use and distribution terms for this software are covered by the
+// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
+// which can be found in the file CPL.TXT at the root of this distribution.
+// By using this software in any fashion, you are agreeing to be bound by
+// the terms of this license. You must not remove this notice, or
+// any other, from this software.
+
+#ifndef __ATLWINX_H__
+#define __ATLWINX_H__
+
+#pragma once
+
+#ifndef __ATLAPP_H__
+ #error atlwinx.h requires atlapp.h to be included first
+#endif
+
+#if (_ATL_VER >= 0x0700)
+ #include <atlwin.h>
+#endif // (_ATL_VER >= 0x0700)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes in this file:
+//
+// _U_RECT
+// _U_MENUorID
+// _U_STRINGorID
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Command Chaining Macros
+
+#define CHAIN_COMMANDS(theChainClass) \
+ if(uMsg == WM_COMMAND) \
+ CHAIN_MSG_MAP(theChainClass)
+
+#define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \
+ if(uMsg == WM_COMMAND) \
+ CHAIN_MSG_MAP_ALT(theChainClass, msgMapID)
+
+#define CHAIN_COMMANDS_MEMBER(theChainMember) \
+ if(uMsg == WM_COMMAND) \
+ CHAIN_MSG_MAP_MEMBER(theChainMember)
+
+#define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \
+ if(uMsg == WM_COMMAND) \
+ CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Macros for parent message map to selectively reflect control messages
+
+// NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot
+// (and overridden in 2 cases - CContainedWindowT and CAxHostWindow)
+// Since we can't modify ATL, we'll provide the needed additions
+// in a separate function (that is not a member of CWindowImplRoot)
+
+namespace WTL
+{
+
+inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled,
+ UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL)
+{
+ if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg))
+ {
+ // The notification message doesn't match the filter.
+ bHandled = FALSE;
+ return 1;
+ }
+
+ HWND hWndChild = NULL;
+ UINT_PTR idFrom = 0;
+
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ if(lParam != NULL) // not from a menu
+ {
+ hWndChild = (HWND)lParam;
+ idFrom = (UINT_PTR)LOWORD(wParam);
+ }
+ break;
+ case WM_NOTIFY:
+ hWndChild = ((LPNMHDR)lParam)->hwndFrom;
+ idFrom = ((LPNMHDR)lParam)->idFrom;
+ break;
+#ifndef _WIN32_WCE
+ case WM_PARENTNOTIFY:
+ switch(LOWORD(wParam))
+ {
+ case WM_CREATE:
+ case WM_DESTROY:
+ hWndChild = (HWND)lParam;
+ idFrom = (UINT_PTR)HIWORD(wParam);
+ break;
+ default:
+ hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam));
+ idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);
+ break;
+ }
+ break;
+#endif // !_WIN32_WCE
+ case WM_DRAWITEM:
+ if(wParam) // not from a menu
+ {
+ hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem;
+ idFrom = (UINT_PTR)wParam;
+ }
+ break;
+ case WM_MEASUREITEM:
+ if(wParam) // not from a menu
+ {
+ hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID);
+ idFrom = (UINT_PTR)wParam;
+ }
+ break;
+ case WM_COMPAREITEM:
+ if(wParam) // not from a menu
+ {
+ hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem;
+ idFrom = (UINT_PTR)wParam;
+ }
+ break;
+ case WM_DELETEITEM:
+ if(wParam) // not from a menu
+ {
+ hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem;
+ idFrom = (UINT_PTR)wParam;
+ }
+ break;
+ case WM_VKEYTOITEM:
+ case WM_CHARTOITEM:
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ hWndChild = (HWND)lParam;
+ idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);
+ 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;
+ idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);
+ break;
+ default:
+ break;
+ }
+
+ if((hWndChild == NULL) ||
+ ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild)))
+ {
+ // Either hWndChild isn't valid, or
+ // hWndChild doesn't match the filter.
+ bHandled = FALSE;
+ return 1;
+ }
+
+ if((idFromFilter != 0) && (idFromFilter != idFrom))
+ {
+ // The dialog control id doesn't match the filter.
+ bHandled = FALSE;
+ return 1;
+ }
+
+ ATLASSERT(::IsWindow(hWndChild));
+ LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
+ if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC))
+ {
+ // Try to prevent problems with WM_CTLCOLOR* messages when
+ // the message wasn't really handled
+ bHandled = FALSE;
+ }
+
+ return lResult;
+}
+
+}; // namespace WTL
+
+// Try to prevent problems with WM_CTLCOLOR* messages when
+// the message wasn't really handled
+#define REFLECT_NOTIFICATIONS_EX() \
+{ \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \
+ bHandled = FALSE; \
+ if(bHandled) \
+ return TRUE; \
+}
+
+#define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_COMMAND(id, code) \
+ if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_COMMAND_ID(id) \
+ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_COMMAND_CODE(code) \
+ if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_COMMAND_RANGE(idFirst, idLast) \
+ if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \
+ if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFY(id, cd) \
+ if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFY_ID(id) \
+ if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFY_CODE(cd) \
+ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFY_RANGE(idFirst, idLast) \
+ if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \
+ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Reflected message handler macros for message maps (for ATL 3.0)
+
+#if (_ATL_VER < 0x0700)
+
+#define REFLECTED_COMMAND_HANDLER(id, code, func) \
+ if(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_COMMAND_ID_HANDLER(id, func) \
+ if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_COMMAND_CODE_HANDLER(code, func) \
+ if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \
+ { \
+ bHandled = TRUE; \
+ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \
+ if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \
+ if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_NOTIFY_HANDLER(id, cd, func) \
+ if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_NOTIFY_ID_HANDLER(id, func) \
+ if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \
+ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \
+ if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \
+ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
+ { \
+ bHandled = TRUE; \
+ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+#endif // (_ATL_VER < 0x0700)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Dual argument helper classes (for ATL 3.0)
+
+#if (_ATL_VER < 0x0700)
+
+namespace ATL
+{
+
+class _U_RECT
+{
+public:
+ _U_RECT(LPRECT lpRect) : m_lpRect(lpRect)
+ { }
+ _U_RECT(RECT& rc) : m_lpRect(&rc)
+ { }
+ LPRECT m_lpRect;
+};
+
+class _U_MENUorID
+{
+public:
+ _U_MENUorID(HMENU hMenu) : m_hMenu(hMenu)
+ { }
+ _U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID))
+ { }
+ HMENU m_hMenu;
+};
+
+class _U_STRINGorID
+{
+public:
+ _U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString)
+ { }
+ _U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID))
+ { }
+ LPCTSTR m_lpstr;
+};
+
+}; // namespace ATL
+
+#endif // (_ATL_VER < 0x0700)
+
+
+namespace WTL
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward notifications support for message maps (for ATL 3.0)
+
+#if (_ATL_VER < 0x0700)
+
+// forward notifications support
+#define FORWARD_NOTIFICATIONS() \
+ { \
+ bHandled = TRUE; \
+ lResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \
+ if(bHandled) \
+ return TRUE; \
+ }
+
+static LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+ LRESULT lResult = 0;
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ case WM_NOTIFY:
+#ifndef _WIN32_WCE
+ case WM_PARENTNOTIFY:
+#endif // !_WIN32_WCE
+ case WM_DRAWITEM:
+ case WM_MEASUREITEM:
+ case WM_COMPAREITEM:
+ case WM_DELETEITEM:
+ case WM_VKEYTOITEM:
+ case WM_CHARTOITEM:
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ lResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam);
+ break;
+ default:
+ bHandled = FALSE;
+ break;
+ }
+ return lResult;
+}
+
+#endif // (_ATL_VER < 0x0700)
+
+}; // namespace WTL
+
+#endif // __ATLWINX_H__