- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / wtl / include / atlframe.h
1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
8
9 #ifndef __ATLFRAME_H__
10 #define __ATLFRAME_H__
11
12 #pragma once
13
14 #ifndef __cplusplus
15         #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
17
18 #ifndef __ATLAPP_H__
19         #error atlframe.h requires atlapp.h to be included first
20 #endif
21
22 #ifndef __ATLWIN_H__
23         #error atlframe.h requires atlwin.h to be included first
24 #endif
25
26
27 ///////////////////////////////////////////////////////////////////////////////
28 // Classes in this file:
29 //
30 // CFrameWindowImpl<T, TBase, TWinTraits>
31 // CMDIWindow
32 // CMDIFrameWindowImpl<T, TBase, TWinTraits>
33 // CMDIChildWindowImpl<T, TBase, TWinTraits>
34 // COwnerDraw<T>
35 // CUpdateUIBase
36 // CUpdateUI<T>
37 // CDynamicUpdateUI<T>
38 // CDialogResize<T>
39 // CDoubleBufferImpl<T>
40 // CDoubleBufferWindowImpl<T, TBase, TWinTraits>
41 //
42 // Global functions:
43 //   AtlCreateSimpleToolBar()
44
45
46 namespace WTL
47 {
48
49 ///////////////////////////////////////////////////////////////////////////////
50 // CFrameWndClassInfo - Manages frame window Windows class information
51
52 class CFrameWndClassInfo
53 {
54 public:
55 #ifndef _WIN32_WCE
56         enum { cchAutoName = 5 + sizeof(void*) * 2 };   // sizeof(void*) * 2 is the number of digits %p outputs
57         WNDCLASSEX m_wc;
58 #else // CE specific
59         enum { cchAutoName = MAX_PATH };   // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string.
60         WNDCLASS m_wc;
61 #endif // !_WIN32_WCE
62         LPCTSTR m_lpszOrigName;
63         WNDPROC pWndProc;
64         LPCTSTR m_lpszCursorID;
65         BOOL m_bSystemCursor;
66         ATOM m_atom;
67         TCHAR m_szAutoName[cchAutoName];
68         UINT m_uCommonResourceID;
69
70 #ifndef _WIN32_WCE
71         ATOM Register(WNDPROC* pProc)
72         {
73                 if (m_atom == 0)
74                 {
75                         CWindowCreateCriticalSectionLock lock;
76                         if(FAILED(lock.Lock()))
77                         {
78                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
79                                 ATLASSERT(FALSE);
80                                 return 0;
81                         }
82
83                         if(m_atom == 0)
84                         {
85                                 HINSTANCE hInst = ModuleHelper::GetModuleInstance();
86
87                                 if (m_lpszOrigName != NULL)
88                                 {
89                                         ATLASSERT(pProc != NULL);
90                                         LPCTSTR lpsz = m_wc.lpszClassName;
91                                         WNDPROC proc = m_wc.lpfnWndProc;
92
93                                         WNDCLASSEX wc = { 0 };
94                                         wc.cbSize = sizeof(WNDCLASSEX);
95                                         // try process local class first
96                                         if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
97                                         {
98                                                 // try global class
99                                                 if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))
100                                                 {
101                                                         lock.Unlock();
102                                                         return 0;
103                                                 }
104                                         }
105                                         m_wc = wc;
106                                         pWndProc = m_wc.lpfnWndProc;
107                                         m_wc.lpszClassName = lpsz;
108                                         m_wc.lpfnWndProc = proc;
109                                 }
110                                 else
111                                 {
112                                         m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
113                                 }
114
115                                 m_wc.hInstance = hInst;
116                                 m_wc.style &= ~CS_GLOBALCLASS;   // we don't register global classes
117                                 if (m_wc.lpszClassName == NULL)
118                                 {
119 #if (_WIN32_WINNT >= 0x0500) || defined(_WIN64)
120                                         SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc);
121 #else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
122                                         SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
123 #endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
124                                         m_wc.lpszClassName = m_szAutoName;
125                                 }
126
127                                 WNDCLASSEX wcTemp = m_wc;
128                                 m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
129                                 if (m_atom == 0)
130                                 {
131                                         if(m_uCommonResourceID != 0)   // use it if not zero
132                                         {
133                                                 m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
134                                                 m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
135                                         }
136                                         m_atom = ::RegisterClassEx(&m_wc);
137                                 }
138                         }
139
140                         lock.Unlock();
141                 }
142
143                 if (m_lpszOrigName != NULL)
144                 {
145                         ATLASSERT(pProc != NULL);
146                         ATLASSERT(pWndProc != NULL);
147                         *pProc = pWndProc;
148                 }
149
150                 return m_atom;
151         }
152 #else // CE specific
153         ATOM Register(WNDPROC* pProc)
154         {
155                 if (m_atom == 0)
156                 {
157                         CWindowCreateCriticalSectionLock lock;
158                         if(FAILED(lock.Lock()))
159                         {
160                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
161                                 ATLASSERT(FALSE);
162                                 return 0;
163                         }
164
165                         if(m_atom == 0)
166                         {
167                                 HINSTANCE hInst = ModuleHelper::GetModuleInstance();
168
169                                 if (m_lpszOrigName != NULL)
170                                 {
171                                         ATLASSERT(pProc != NULL);
172                                         LPCTSTR lpsz = m_wc.lpszClassName;
173                                         WNDPROC proc = m_wc.lpfnWndProc;
174
175                                         WNDCLASS wc = { 0 };
176                                         // try process local class first
177                                         if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
178                                         {
179                                                 // try global class
180                                                 if(!::GetClassInfo(NULL, m_lpszOrigName, &wc))
181                                                 {
182                                                         lock.Unlock();
183                                                         return 0;
184                                                 }
185                                         }
186                                         m_wc = wc;
187                                         pWndProc = m_wc.lpfnWndProc;
188                                         m_wc.lpszClassName = lpsz;
189                                         m_wc.lpfnWndProc = proc;
190                                 }
191                                 else
192                                 {
193 #if defined(GWES_CURSOR) || defined(GWES_MCURSOR)
194                                         m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
195 #else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
196                                         m_wc.hCursor = NULL;
197 #endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
198                                 }
199
200                                 m_wc.hInstance = hInst;
201                                 m_wc.style &= ~CS_GLOBALCLASS;   // we don't register global classes
202                                 if (m_wc.lpszClassName == NULL)
203                                 {
204                                         wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
205                                         m_wc.lpszClassName = m_szAutoName;
206                                 }
207
208                                 WNDCLASS wcTemp = m_wc;
209                                 m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
210                                 if (m_atom == 0)
211                                 {
212                                         if(m_uCommonResourceID != 0)   // use it if not zero
213                                                 m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
214                                         m_atom = ::RegisterClass(&m_wc);
215                                 }
216                         }
217
218                         lock.Unlock();
219                 }
220
221                 if (m_lpszOrigName != NULL)
222                 {
223                         ATLASSERT(pProc != NULL);
224                         ATLASSERT(pWndProc != NULL);
225                         *pProc = pWndProc;
226                 }
227
228                 return m_atom;
229         }
230 #endif // _WIN32_WCE
231 };
232
233
234 ///////////////////////////////////////////////////////////////////////////////
235 // Macros for declaring frame window WNDCLASS
236
237 #ifndef _WIN32_WCE
238
239 #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
240 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
241 { \
242         static WTL::CFrameWndClassInfo wc = \
243         { \
244                 { sizeof(WNDCLASSEX), 0, StartWindowProc, \
245                   0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
246                 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
247         }; \
248         return wc; \
249 }
250
251 #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
252 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
253 { \
254         static WTL::CFrameWndClassInfo wc = \
255         { \
256                 { sizeof(WNDCLASSEX), style, StartWindowProc, \
257                   0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
258                 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
259         }; \
260         return wc; \
261 }
262
263 #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
264 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
265 { \
266         static WTL::CFrameWndClassInfo wc = \
267         { \
268                 { sizeof(WNDCLASSEX), 0, StartWindowProc, \
269                   0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
270                 OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
271         }; \
272         return wc; \
273 }
274
275 #else // CE specific
276
277 #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
278 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
279 { \
280         static WTL::CFrameWndClassInfo wc = \
281         { \
282                 { 0, StartWindowProc, \
283                   0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \
284                 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
285         }; \
286         return wc; \
287 }
288
289 #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
290 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
291 { \
292         static WTL::CFrameWndClassInfo wc = \
293         { \
294                 { style, StartWindowProc, \
295                   0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \
296                 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
297         }; \
298         return wc; \
299 }
300
301 #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
302 static WTL::CFrameWndClassInfo& GetWndClassInfo() \
303 { \
304         static WTL::CFrameWndClassInfo wc = \
305         { \
306                 { NULL, StartWindowProc, \
307                   0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \
308                 OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
309         }; \
310         return wc; \
311 }
312
313 #endif // !_WIN32_WCE
314
315
316 ///////////////////////////////////////////////////////////////////////////////
317 // CFrameWindowImpl
318
319 // Client window command chaining macro (only for frame windows)
320 #define CHAIN_CLIENT_COMMANDS() \
321         if(uMsg == WM_COMMAND && m_hWndClient != NULL) \
322                 ::SendMessage(m_hWndClient, uMsg, wParam, lParam);
323
324 // standard toolbar styles
325 #define ATL_SIMPLE_TOOLBAR_STYLE \
326         (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)
327 // toolbar in a rebar pane
328 #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \
329         (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)
330 // standard rebar styles
331 #if (_WIN32_IE >= 0x0400)
332   #define ATL_SIMPLE_REBAR_STYLE \
333         (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)
334 #else
335   #define ATL_SIMPLE_REBAR_STYLE \
336         (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS)
337 #endif // !(_WIN32_IE >= 0x0400)
338 // rebar without borders
339 #if (_WIN32_IE >= 0x0400)
340   #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
341         (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)
342 #else
343   #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
344         (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER)
345 #endif // !(_WIN32_IE >= 0x0400)
346
347 // command bar support
348 #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
349
350 #define CBRM_GETCMDBAR                  (WM_USER + 301) // returns command bar HWND
351 #define CBRM_GETMENU                    (WM_USER + 302) // returns loaded or attached menu
352 #define CBRM_TRACKPOPUPMENU             (WM_USER + 303) // displays a popup menu
353
354 struct _AtlFrameWnd_CmdBarPopupMenu
355 {
356         int cbSize;
357         HMENU hMenu;
358         UINT uFlags;
359         int x;
360         int y;
361         LPTPMPARAMS lptpm;
362 };
363
364 #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu
365
366 #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
367
368
369 template <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
370 class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits >
371 {
372 public:
373         DECLARE_FRAME_WND_CLASS(NULL, 0)
374
375 // Data members
376         HWND m_hWndToolBar;
377         HWND m_hWndStatusBar;
378         HWND m_hWndClient;
379
380         HACCEL m_hAccel;
381
382 #ifdef _WIN32_WCE
383         HWND m_hWndCECommandBar;
384 #endif // _WIN32_WCE
385
386         struct _AtlToolBarData
387         {
388                 WORD wVersion;
389                 WORD wWidth;
390                 WORD wHeight;
391                 WORD wItemCount;
392                 //WORD aItems[wItemCount]
393
394                 WORD* items()
395                         { return (WORD*)(this+1); }
396         };
397
398 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
399         struct _ChevronMenuInfo
400         {
401                 HMENU hMenu;
402                 LPNMREBARCHEVRON lpnm;
403                 bool bCmdBar;
404         };
405 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
406
407 // Constructor
408         CFrameWindowImplBase() : 
409 #ifdef _WIN32_WCE
410                 m_hWndCECommandBar(NULL),
411 #endif // _WIN32_WCE
412                 m_hWndToolBar(NULL), 
413                 m_hWndStatusBar(NULL), 
414                 m_hWndClient(NULL), 
415                 m_hAccel(NULL)
416         { }
417
418 // Methods
419         HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
420         {
421                 ATLASSERT(m_hWnd == NULL);
422
423                 if(atom == 0)
424                         return NULL;
425
426                 ModuleHelper::AddCreateWndData(&m_thunk.cd, this);
427
428                 if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD))
429                         MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
430                 if(rect.m_lpRect == NULL)
431                         rect.m_lpRect = &TBase::rcDefault;
432
433                 HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,
434                         dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,
435                         rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,
436                         ModuleHelper::GetModuleInstance(), lpCreateParam);
437
438                 ATLASSERT(hWnd == NULL || m_hWnd == hWnd);
439
440                 return hWnd;
441         }
442
443         static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, 
444                         DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
445         {
446                 HINSTANCE hInst = ModuleHelper::GetResourceInstance();
447                 HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);
448                 if (hRsrc == NULL)
449                         return NULL;
450
451                 HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
452                 if (hGlobal == NULL)
453                         return NULL;
454
455                 _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);
456                 if (pData == NULL)
457                         return NULL;
458                 ATLASSERT(pData->wVersion == 1);
459
460                 WORD* pItems = pData->items();
461                 int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);
462                 CTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff;
463                 TBBUTTON* pTBBtn = buff.Allocate(nItems);
464                 ATLASSERT(pTBBtn != NULL);
465                 if(pTBBtn == NULL)
466                         return NULL;
467
468                 const int cxSeparator = 8;
469
470                 // set initial separator (half width)
471                 if(bInitialSeparator)
472                 {
473                         pTBBtn[0].iBitmap = cxSeparator / 2;
474                         pTBBtn[0].idCommand = 0;
475                         pTBBtn[0].fsState = 0;
476                         pTBBtn[0].fsStyle = TBSTYLE_SEP;
477                         pTBBtn[0].dwData = 0;
478                         pTBBtn[0].iString = 0;
479                 }
480
481                 int nBmp = 0;
482                 for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)
483                 {
484                         if(pItems[i] != 0)
485                         {
486                                 pTBBtn[j].iBitmap = nBmp++;
487                                 pTBBtn[j].idCommand = pItems[i];
488                                 pTBBtn[j].fsState = TBSTATE_ENABLED;
489                                 pTBBtn[j].fsStyle = TBSTYLE_BUTTON;
490                                 pTBBtn[j].dwData = 0;
491                                 pTBBtn[j].iString = 0;
492                         }
493                         else
494                         {
495                                 pTBBtn[j].iBitmap = cxSeparator;
496                                 pTBBtn[j].idCommand = 0;
497                                 pTBBtn[j].fsState = 0;
498                                 pTBBtn[j].fsStyle = TBSTYLE_SEP;
499                                 pTBBtn[j].dwData = 0;
500                                 pTBBtn[j].iString = 0;
501                         }
502                 }
503
504 #ifndef _WIN32_WCE
505                 HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
506                 if(hWnd == NULL)
507                 {
508                         ATLASSERT(FALSE);
509                         return NULL;
510                 }
511 #else // CE specific
512                 dwStyle;
513                 nID;
514                 // The toolbar must go onto the existing CommandBar or MenuBar
515                 HWND hWnd = hWndParent;
516 #endif // _WIN32_WCE
517
518                 ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);
519
520                 // check if font is taller than our bitmaps
521                 CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
522                 if(font.IsNull())
523                         font = AtlGetDefaultGuiFont();
524                 LOGFONT lf = { 0 };
525                 font.GetLogFont(lf);
526                 WORD cyFontHeight = (WORD)abs(lf.lfHeight);
527
528 #ifndef _WIN32_WCE
529                 WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID);
530                 if(bitsPerPixel > 4)
531                 {
532                         COLORREF crMask = CLR_DEFAULT;
533                         if(bitsPerPixel == 32)
534                         {
535                                 // 32-bit color bitmap with alpha channel (valid for Windows XP and later)
536                                 crMask = CLR_NONE;
537                         }
538                         HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
539                         ATLASSERT(hImageList != NULL);
540                         ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList);
541                 }
542                 else
543 #endif // !_WIN32_WCE
544                 {
545                         TBADDBITMAP tbab = { 0 };
546                         tbab.hInst = hInst;
547                         tbab.nID = nResourceID;
548                         ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);
549                 }
550
551                 ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);
552                 ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight)));
553                 const int cxyButtonMargin = 7;
554                 ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin));
555
556                 return hWnd;
557         }
558
559 #ifndef _WIN32_WCE
560         static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
561         {
562                 // Ensure style combinations for proper rebar painting
563                 if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER)
564                         dwStyle &= ~WS_BORDER;
565                 else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))
566                         dwStyle |= CCS_NODIVIDER;
567
568                 // Create rebar window
569                 HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
570                 if(hWndReBar == NULL)
571                 {
572                         ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n"));
573                         return NULL;
574                 }
575
576                 // Initialize and send the REBARINFO structure
577                 REBARINFO rbi = { 0 };
578                 rbi.cbSize = sizeof(REBARINFO);
579                 rbi.fMask  = 0;
580                 if(!::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi))
581                 {
582                         ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n"));
583                         ::DestroyWindow(hWndReBar);
584                         return NULL;
585                 }
586
587                 return hWndReBar;
588         }
589
590         BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
591         {
592                 ATLASSERT(!::IsWindow(m_hWndToolBar));
593                 m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID);
594                 return (m_hWndToolBar != NULL);
595         }
596
597         static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
598         {
599                 ATLASSERT(::IsWindow(hWndReBar));   // must be already created
600 #ifdef _DEBUG
601                 // block - check if this is really a rebar
602                 {
603                         TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 };
604                         ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));
605                         ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);
606                 }
607 #endif // _DEBUG
608                 ATLASSERT(::IsWindow(hWndBand));   // must be already created
609
610                 // Get number of buttons on the toolbar
611                 int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);
612
613                 // Set band info structure
614                 REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
615 #if (_WIN32_IE >= 0x0400)
616                 rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;
617 #else
618                 rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE;
619 #endif // !(_WIN32_IE >= 0x0400)
620                 if(lpstrTitle != NULL)
621                         rbBand.fMask |= RBBIM_TEXT;
622                 rbBand.fStyle = RBBS_CHILDEDGE;
623 #if (_WIN32_IE >= 0x0500)
624                 if(nBtnCount > 0)   // add chevron style for toolbar with buttons
625                         rbBand.fStyle |= RBBS_USECHEVRON;
626 #endif // (_WIN32_IE >= 0x0500)
627                 if(bNewRow)
628                         rbBand.fStyle |= RBBS_BREAK;
629
630                 rbBand.lpText = (LPTSTR)lpstrTitle;
631                 rbBand.hwndChild = hWndBand;
632                 if(nID == 0)   // calc band ID
633                         nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
634                 rbBand.wID = nID;
635
636                 // Calculate the size of the band
637                 BOOL bRet = FALSE;
638                 RECT rcTmp = { 0 };
639                 if(nBtnCount > 0)
640                 {
641                         bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);
642                         ATLASSERT(bRet);
643                         rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;
644                         rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
645                         if(bFullWidthAlways)
646                         {
647                                 rbBand.cxMinChild = rbBand.cx;
648                         }
649                         else if(lpstrTitle == NULL)
650                         {
651                                 bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);
652                                 ATLASSERT(bRet);
653                                 rbBand.cxMinChild = rcTmp.right;
654                         }
655                         else
656                         {
657                                 rbBand.cxMinChild = 0;
658                         }
659                 }
660                 else    // no buttons, either not a toolbar or really has no buttons
661                 {
662                         bRet = ::GetWindowRect(hWndBand, &rcTmp);
663                         ATLASSERT(bRet);
664                         rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);
665                         rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0;
666                         rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
667                 }
668
669 #if (_WIN32_IE >= 0x0400)
670                 rbBand.cxIdeal = rbBand.cx;
671 #endif // (_WIN32_IE >= 0x0400)
672
673                 // Add the band
674                 LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
675                 if(lRes == 0)
676                 {
677                         ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n"));
678                         return FALSE;
679                 }
680
681 #if (_WIN32_IE >= 0x0501)
682                 DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L);
683                 ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS);
684 #endif // (_WIN32_IE >= 0x0501)
685
686                 return TRUE;
687         }
688
689         BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
690         {
691                 ATLASSERT(::IsWindow(m_hWndToolBar));   // must be an existing rebar
692                 ATLASSERT(::IsWindow(hWndBand));        // must be created
693                 return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);
694         }
695
696 #if (_WIN32_IE >= 0x0400)
697         void SizeSimpleReBarBands()
698         {
699                 ATLASSERT(::IsWindow(m_hWndToolBar));   // must be an existing rebar
700
701                 int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);
702
703                 for(int i = 0; i < nCount; i++)
704                 {
705                         REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
706                         rbBand.fMask = RBBIM_SIZE;
707                         BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);
708                         ATLASSERT(bRet);
709                         RECT rect = { 0, 0, 0, 0 };
710                         ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);
711                         rbBand.cx += rect.left + rect.right;
712                         bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);
713                         ATLASSERT(bRet);
714                 }
715         }
716 #endif // (_WIN32_IE >= 0x0400)
717 #endif // _WIN32_WCE
718
719 #ifndef _WIN32_WCE
720         BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
721 #else // CE specific
722         BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
723 #endif // _WIN32_WCE
724         {
725                 ATLASSERT(!::IsWindow(m_hWndStatusBar));
726                 m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);
727                 return (m_hWndStatusBar != NULL);
728         }
729
730 #ifndef _WIN32_WCE
731         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)
732 #else // CE specific
733         BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
734 #endif // _WIN32_WCE
735         {
736                 const int cchMax = 128;   // max text length is 127 for status bars (+1 for null)
737                 TCHAR szText[cchMax];
738                 szText[0] = 0;
739                 ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
740                 return CreateSimpleStatusBar(szText, dwStyle, nID);
741         }
742
743 #ifdef _WIN32_WCE
744         BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1)
745         {
746                 ATLASSERT(m_hWndCECommandBar == NULL);
747                 ATLASSERT(m_hWndToolBar == NULL);
748
749                 m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID);
750                 if(m_hWndCECommandBar == NULL)
751                         return FALSE;
752
753                 m_hWndToolBar = m_hWndCECommandBar;
754
755                 BOOL bRet = TRUE;
756
757                 if(pszMenu != NULL)
758                         bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton);
759
760                 bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0);
761
762                 return bRet;
763         }
764
765 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
766         BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0)
767         {
768                 ATLASSERT(m_hWndCECommandBar == NULL);
769
770                 SHMENUBARINFO mbi = { 0 };
771                 mbi.cbSize = sizeof(mbi);
772                 mbi.hwndParent = m_hWnd;
773                 mbi.dwFlags = dwFlags;
774                 mbi.nToolBarId = nToolBarId;
775                 mbi.hInstRes  = ModuleHelper::GetResourceInstance();
776                 mbi.nBmpId = nBmpId;
777                 mbi.cBmpImages = cBmpImages;
778                 mbi.hwndMB = NULL;   // This gets set by SHCreateMenuBar
779
780                 BOOL bRet = ::SHCreateMenuBar(&mbi);
781                 if(bRet != FALSE)
782                 {
783                         m_hWndCECommandBar = mbi.hwndMB;
784                         SizeToMenuBar();
785                 }
786
787                 return bRet;
788         }
789
790         void SizeToMenuBar()   // for menu bar only
791         {
792                 ATLASSERT(::IsWindow(m_hWnd));
793                 ATLASSERT(::IsWindow(m_hWndCECommandBar));
794
795                 RECT rect = { 0 };
796                 GetWindowRect(&rect);
797                 RECT rectMB = { 0 };
798                 ::GetWindowRect(m_hWndCECommandBar, &rectMB);
799                 int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top;
800                 SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE);
801         }
802 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
803 #endif // _WIN32_WCE
804
805         void UpdateLayout(BOOL bResizeBars = TRUE)
806         {
807                 RECT rect = { 0 };
808                 GetClientRect(&rect);
809
810                 // position bars and offset their dimensions
811                 UpdateBarsPosition(rect, bResizeBars);
812
813                 // resize client window
814                 if(m_hWndClient != NULL)
815                         ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
816                                 rect.right - rect.left, rect.bottom - rect.top,
817                                 SWP_NOZORDER | SWP_NOACTIVATE);
818         }
819
820         void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
821         {
822                 // resize toolbar
823                 if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
824                 {
825                         if(bResizeBars)
826                         {
827                                 ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
828                                 ::InvalidateRect(m_hWndToolBar, NULL, FALSE);
829                         }
830                         RECT rectTB = { 0 };
831                         ::GetWindowRect(m_hWndToolBar, &rectTB);
832                         rect.top += rectTB.bottom - rectTB.top;
833                 }
834
835                 // resize status bar
836                 if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
837                 {
838                         if(bResizeBars)
839                                 ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
840                         RECT rectSB = { 0 };
841                         ::GetWindowRect(m_hWndStatusBar, &rectSB);
842                         rect.bottom -= rectSB.bottom - rectSB.top;
843                 }
844         }
845
846         BOOL PreTranslateMessage(MSG* pMsg)
847         {
848                 if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
849                         return TRUE;
850                 return FALSE;
851         }
852
853         BEGIN_MSG_MAP(CFrameWindowImplBase)
854                 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
855 #ifndef _WIN32_WCE
856                 MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
857 #endif // !_WIN32_WCE
858                 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
859                 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
860 #ifndef _WIN32_WCE
861                 NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)
862                 NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)
863 #endif // !_WIN32_WCE
864         END_MSG_MAP()
865
866         LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
867         {
868                 if(m_hWndClient != NULL)   // view will paint itself instead
869                         return 1;
870
871                 bHandled = FALSE;
872                 return 0;
873         }
874
875 #ifndef _WIN32_WCE
876         LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
877         {
878                 bHandled = FALSE;
879
880                 if(m_hWndStatusBar == NULL)
881                         return 1;
882
883                 WORD wFlags = HIWORD(wParam);
884                 if(wFlags == 0xFFFF && lParam == NULL)   // menu closing
885                 {
886                         ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);
887                 }
888                 else
889                 {
890                         const int cchBuff = 256;
891                         TCHAR szBuff[cchBuff];
892                         szBuff[0] = 0;
893                         if(!(wFlags & MF_POPUP))
894                         {
895                                 WORD wID = LOWORD(wParam);
896                                 // check for special cases
897                                 if(wID >= 0xF000 && wID < 0xF1F0)   // system menu IDs
898                                         wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);
899                                 else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST)   // MRU items
900                                         wID = ATL_IDS_MRU_FILE;
901                                 else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD)   // MDI child windows
902                                         wID = ATL_IDS_MDICHILD;
903
904                                 int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff);
905                                 for(int i = 0; i < nRet; i++)
906                                 {
907                                         if(szBuff[i] == _T('\n'))
908                                         {
909                                                 szBuff[i] = 0;
910                                                 break;
911                                         }
912                                 }
913                         }
914                         ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);
915                         ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);
916                 }
917
918                 return 1;
919         }
920 #endif // !_WIN32_WCE
921
922         LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)
923         {
924                 if(m_hWndClient != NULL)
925                         ::SetFocus(m_hWndClient);
926
927                 bHandled = FALSE;
928                 return 1;
929         }
930
931         LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
932         {
933                 if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0)
934                         ::PostQuitMessage(1);
935
936                 bHandled = FALSE;
937                 return 1;
938         }
939
940 #ifndef _WIN32_WCE
941         LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
942         {
943                 LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;
944                 pDispInfo->szText[0] = 0;
945
946                 if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
947                 {
948                         const int cchBuff = 256;
949                         char szBuff[cchBuff];
950                         szBuff[0] = 0;
951                         int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
952                         for(int i = 0; i < nRet; i++)
953                         {
954                                 if(szBuff[i] == '\n')
955                                 {
956                                         SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
957                                         break;
958                                 }
959                         }
960 #if (_WIN32_IE >= 0x0300)
961                         if(nRet > 0)   // string was loaded, save it
962                                 pDispInfo->uFlags |= TTF_DI_SETITEM;
963 #endif // (_WIN32_IE >= 0x0300)
964                 }
965
966                 return 0;
967         }
968
969         LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
970         {
971                 LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;
972                 pDispInfo->szText[0] = 0;
973
974                 if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
975                 {
976                         const int cchBuff = 256;
977                         wchar_t szBuff[cchBuff];
978                         szBuff[0] = 0;
979                         int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
980                         for(int i = 0; i < nRet; i++)
981                         {
982                                 if(szBuff[i] == L'\n')
983                                 {
984                                         SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
985                                         break;
986                                 }
987                         }
988 #if (_WIN32_IE >= 0x0300)
989                         if(nRet > 0)   // string was loaded, save it
990                                 pDispInfo->uFlags |= TTF_DI_SETITEM;
991 #endif // (_WIN32_IE >= 0x0300)
992                 }
993
994                 return 0;
995         }
996 #endif // !_WIN32_WCE
997
998 // Implementation - chevron menu support
999 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1000         bool PrepareChevronMenu(_ChevronMenuInfo& cmi)
1001         {
1002                 // get rebar and toolbar
1003                 REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };
1004                 rbbi.fMask = RBBIM_CHILD;
1005                 BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
1006                 ATLASSERT(bRet);
1007
1008                 // assume the band is a toolbar
1009                 ATL::CWindow wnd = rbbi.hwndChild;
1010                 int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
1011                 if(nCount <= 0)   // probably not a toolbar
1012                         return false;
1013
1014                 // check if it's a command bar
1015                 CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
1016                 cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);
1017
1018                 // build a menu from hidden items
1019                 CMenuHandle menu;
1020                 bRet = menu.CreatePopupMenu();
1021                 ATLASSERT(bRet);
1022                 RECT rcClient = { 0 };
1023                 bRet = wnd.GetClientRect(&rcClient);
1024                 ATLASSERT(bRet);
1025                 for(int i = 0; i < nCount; i++)
1026                 {
1027                         TBBUTTON tbb = { 0 };
1028                         bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
1029                         ATLASSERT(bRet);
1030                         // skip hidden buttons
1031                         if((tbb.fsState & TBSTATE_HIDDEN) != 0)
1032                                 continue;
1033                         RECT rcButton = { 0 };
1034                         bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
1035                         ATLASSERT(bRet);
1036                         bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
1037                         if(rcButton.right > rcClient.right)
1038                         {
1039                                 if(tbb.fsStyle & BTNS_SEP)
1040                                 {
1041                                         if(menu.GetMenuItemCount() > 0)
1042                                                 menu.AppendMenu(MF_SEPARATOR);
1043                                 }
1044                                 else if(cmi.bCmdBar)
1045                                 {
1046                                         const int cchBuff = 200;
1047                                         TCHAR szBuff[cchBuff] = { 0 };
1048                                         CMenuItemInfo mii;
1049                                         mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
1050                                         mii.dwTypeData = szBuff;
1051                                         mii.cch = cchBuff;
1052                                         bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
1053                                         ATLASSERT(bRet);
1054                                         // Note: CmdBar currently supports only drop-down items
1055                                         ATLASSERT(::IsMenu(mii.hSubMenu));
1056                                         bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
1057                                         ATLASSERT(bRet);
1058                                 }
1059                                 else
1060                                 {
1061                                         // get button's text
1062                                         const int cchBuff = 200;
1063                                         TCHAR szBuff[cchBuff] = { 0 };
1064                                         LPTSTR lpstrText = szBuff;
1065                                         TBBUTTONINFO tbbi = { 0 };
1066                                         tbbi.cbSize = sizeof(TBBUTTONINFO);
1067                                         tbbi.dwMask = TBIF_TEXT;
1068                                         tbbi.pszText = szBuff;
1069                                         tbbi.cchText = cchBuff;
1070                                         if(wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1 || lstrlen(szBuff) == 0)
1071                                         {
1072                                                 // no text for this button, try a resource string
1073                                                 lpstrText = _T("");
1074                                                 int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff);
1075                                                 for(int n = 0; n < nRet; n++)
1076                                                 {
1077                                                         if(szBuff[n] == _T('\n'))
1078                                                         {
1079                                                                 lpstrText = &szBuff[n + 1];
1080                                                                 break;
1081                                                         }
1082                                                 }
1083                                         }
1084                                         bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
1085                                         ATLASSERT(bRet);
1086                                 }
1087                         }
1088                 }
1089
1090                 if(menu.GetMenuItemCount() == 0)   // no hidden buttons after all
1091                 {
1092                         menu.DestroyMenu();
1093                         ::MessageBeep((UINT)-1);
1094                         return false;
1095                 }
1096
1097                 cmi.hMenu = menu;
1098                 return true;
1099         }
1100
1101         void DisplayChevronMenu(_ChevronMenuInfo& cmi)
1102         {
1103 #ifndef TPM_VERPOSANIMATION
1104                 const UINT TPM_VERPOSANIMATION = 0x1000L;   // Menu animation flag
1105 #endif
1106                 // convert chevron rect to screen coordinates
1107                 ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
1108                 POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom };
1109                 wndFrom.MapWindowPoints(NULL, &pt, 1);
1110                 RECT rc = cmi.lpnm->rc;
1111                 wndFrom.MapWindowPoints(NULL, &rc);
1112                 // set up flags and rect
1113                 UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
1114                 TPMPARAMS TPMParams = { 0 };
1115                 TPMParams.cbSize = sizeof(TPMPARAMS);
1116                 TPMParams.rcExclude = rc;
1117                 // check if this window has a command bar
1118                 HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
1119                 if(::IsWindow(hWndCmdBar))
1120                 {
1121                         CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams };
1122                         ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
1123                 }
1124                 else
1125                 {
1126                         CMenuHandle menu = cmi.hMenu;
1127                         menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams);
1128                 }
1129         }
1130
1131         void CleanupChevronMenu(_ChevronMenuInfo& cmi)
1132         {
1133                 CMenuHandle menu = cmi.hMenu;
1134                 // if menu is from a command bar, detach submenus so they are not destroyed
1135                 if(cmi.bCmdBar)
1136                 {
1137                         for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
1138                                 menu.RemoveMenu(i, MF_BYPOSITION);
1139                 }
1140                 // destroy menu
1141                 menu.DestroyMenu();
1142                 // convert chevron rect to screen coordinates
1143                 ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
1144                 RECT rc = cmi.lpnm->rc;
1145                 wndFrom.MapWindowPoints(NULL, &rc);
1146                 // eat next message if click is on the same button
1147                 MSG msg = { 0 };
1148                 if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt))
1149                         ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
1150         }
1151 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1152 };
1153
1154
1155 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
1156 class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >
1157 {
1158 public:
1159         HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
1160                         DWORD dwStyle = 0, DWORD dwExStyle = 0,
1161                         HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
1162         {
1163                 ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
1164
1165                 dwStyle = T::GetWndStyle(dwStyle);
1166                 dwExStyle = T::GetWndExStyle(dwExStyle);
1167
1168                 if(rect.m_lpRect == NULL)
1169                         rect.m_lpRect = &TBase::rcDefault;
1170
1171                 return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
1172         }
1173
1174         HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
1175         {
1176                 const int cchName = 256;
1177                 TCHAR szWindowName[cchName];
1178                 szWindowName[0] = 0;
1179 #ifndef _WIN32_WCE
1180                 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
1181                 HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
1182 #else // CE specific
1183                 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
1184
1185                 // This always needs to be NULL for Windows CE.
1186                 // Frame Window menus have to go onto the CommandBar.
1187                 // Use CreateSimpleCECommandBar
1188                 HMENU hMenu = NULL;
1189 #endif // _WIN32_WCE
1190
1191                 T* pT = static_cast<T*>(this);
1192                 HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
1193
1194                 if(hWnd != NULL)
1195                         m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
1196
1197                 return hWnd;
1198         }
1199
1200         BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
1201         {
1202                 if(nResourceID == 0)
1203                         nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
1204 #ifndef _WIN32_WCE
1205                 ATLASSERT(!::IsWindow(m_hWndToolBar));
1206                 m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
1207                 return (m_hWndToolBar != NULL);
1208 #else // CE specific
1209                 HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
1210                 return (hWnd != NULL);
1211 #endif // _WIN32_WCE
1212         }
1213
1214 #ifdef _WIN32_WCE
1215         // CE specific variant that returns the handle of the toolbar
1216         HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
1217         {
1218                 if(nResourceID == 0)
1219                         nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
1220
1221                 return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
1222         }
1223 #endif // _WIN32_WCE
1224
1225 // message map and handlers
1226         typedef CFrameWindowImplBase< TBase, TWinTraits >   _baseClass;
1227
1228         BEGIN_MSG_MAP(CFrameWindowImpl)
1229                 MESSAGE_HANDLER(WM_SIZE, OnSize)
1230 #ifndef _ATL_NO_REBAR_SUPPORT
1231 #if (_WIN32_IE >= 0x0400)
1232                 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
1233 #endif // (_WIN32_IE >= 0x0400)
1234 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1235                 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
1236 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1237 #endif // !_ATL_NO_REBAR_SUPPORT
1238                 CHAIN_MSG_MAP(_baseClass)
1239         END_MSG_MAP()
1240
1241         LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1242         {
1243                 if(wParam != SIZE_MINIMIZED)
1244                 {
1245                         T* pT = static_cast<T*>(this);
1246                         pT->UpdateLayout();
1247                 }
1248                 bHandled = FALSE;
1249                 return 1;
1250         }
1251
1252 #ifndef _ATL_NO_REBAR_SUPPORT
1253 #if (_WIN32_IE >= 0x0400)
1254         LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
1255         {
1256                 T* pT = static_cast<T*>(this);
1257                 pT->UpdateLayout(FALSE);
1258                 return 0;
1259         }
1260 #endif // (_WIN32_IE >= 0x0400)
1261
1262 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1263         LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1264         {
1265                 T* pT = static_cast<T*>(this);
1266                 _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
1267                 if(!pT->PrepareChevronMenu(cmi))
1268                 {
1269                         bHandled = FALSE;
1270                         return 1;
1271                 }
1272                 // display a popup menu with hidden items
1273                 pT->DisplayChevronMenu(cmi);
1274                 // cleanup
1275                 pT->CleanupChevronMenu(cmi);
1276                 return 0;
1277         }
1278 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
1279 #endif // !_ATL_NO_REBAR_SUPPORT
1280 };
1281
1282
1283 ///////////////////////////////////////////////////////////////////////////////
1284 // AtlCreateSimpleToolBar - helper for creating simple toolbars
1285
1286 #ifndef _WIN32_WCE
1287
1288 inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, 
1289                 DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
1290 {
1291         return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID);
1292 }
1293
1294 #endif // !_WIN32_WCE
1295
1296
1297 ///////////////////////////////////////////////////////////////////////////////
1298 // CMDIWindow
1299
1300 #ifndef _WIN32_WCE
1301
1302 #ifndef _WTL_MDIWINDOWMENU_TEXT
1303 #define _WTL_MDIWINDOWMENU_TEXT _T("&Window")
1304 #endif
1305
1306 class CMDIWindow : public ATL::CWindow
1307 {
1308 public:
1309 // Data members
1310         HWND m_hWndMDIClient;
1311         HMENU m_hMenu;
1312
1313 // Constructors
1314         CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL)
1315         { }
1316
1317         CMDIWindow& operator =(HWND hWnd)
1318         {
1319                 m_hWnd = hWnd;
1320                 return *this;
1321         }
1322
1323 // Operations
1324         HWND MDIGetActive(BOOL* lpbMaximized = NULL)
1325         {
1326                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1327                 return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);
1328         }
1329
1330         void MDIActivate(HWND hWndChildToActivate)
1331         {
1332                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1333                 ATLASSERT(::IsWindow(hWndChildToActivate));
1334                 ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);
1335         }
1336
1337         void MDINext(HWND hWndChild, BOOL bPrevious = FALSE)
1338         {
1339                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1340                 ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild));
1341                 ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);
1342         }
1343
1344         void MDIMaximize(HWND hWndChildToMaximize)
1345         {
1346                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1347                 ATLASSERT(::IsWindow(hWndChildToMaximize));
1348                 ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);
1349         }
1350
1351         void MDIRestore(HWND hWndChildToRestore)
1352         {
1353                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1354                 ATLASSERT(::IsWindow(hWndChildToRestore));
1355                 ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);
1356         }
1357
1358         void MDIDestroy(HWND hWndChildToDestroy)
1359         {
1360                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1361                 ATLASSERT(::IsWindow(hWndChildToDestroy));
1362                 ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);
1363         }
1364
1365         BOOL MDICascade(UINT uFlags = 0)
1366         {
1367                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1368                 return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);
1369         }
1370
1371         BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)
1372         {
1373                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1374                 return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);
1375         }
1376
1377         void MDIIconArrange()
1378         {
1379                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1380                 ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
1381         }
1382
1383         HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)
1384         {
1385                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1386                 return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);
1387         }
1388
1389         HMENU MDIRefreshMenu()
1390         {
1391                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1392                 return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
1393         }
1394
1395 // Additional operations
1396         static HMENU GetStandardWindowMenu(HMENU hMenu)
1397         {
1398                 int nCount = ::GetMenuItemCount(hMenu);
1399                 if(nCount == -1)
1400                         return NULL;
1401                 int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
1402                 if(nLen == 0)
1403                         return NULL;
1404                 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
1405                 LPTSTR lpszText = buff.Allocate(nLen + 1);
1406                 if(lpszText == NULL)
1407                         return NULL;
1408                 if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
1409                         return NULL;
1410                 if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0)
1411                         return NULL;
1412                 return ::GetSubMenu(hMenu, nCount - 2);
1413         }
1414
1415         void SetMDIFrameMenu()
1416         {
1417                 HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);
1418                 MDISetMenu(m_hMenu, hWindowMenu);
1419                 MDIRefreshMenu();
1420                 ::DrawMenuBar(GetMDIFrame());
1421         }
1422
1423         HWND GetMDIFrame() const
1424         {
1425                 return ::GetParent(m_hWndMDIClient);
1426         }
1427 };
1428
1429 #endif // !_WIN32_WCE
1430
1431
1432 ///////////////////////////////////////////////////////////////////////////////
1433 // CMDIFrameWindowImpl
1434
1435 #ifndef _WIN32_WCE
1436
1437 // MDI child command chaining macro (only for MDI frame windows)
1438 #define CHAIN_MDI_CHILD_COMMANDS() \
1439         if(uMsg == WM_COMMAND) \
1440         { \
1441                 HWND hWndChild = MDIGetActive(); \
1442                 if(hWndChild != NULL) \
1443                         ::SendMessage(hWndChild, uMsg, wParam, lParam); \
1444         }
1445
1446 template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
1447 class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
1448 {
1449 public:
1450         HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
1451                         DWORD dwStyle = 0, DWORD dwExStyle = 0,
1452                         HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
1453         {
1454                 m_hMenu = hMenu;
1455                 ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
1456
1457                 dwStyle = T::GetWndStyle(dwStyle);
1458                 dwExStyle = T::GetWndExStyle(dwExStyle);
1459
1460                 if(rect.m_lpRect == NULL)
1461                         rect.m_lpRect = &TBase::rcDefault;
1462
1463                 return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
1464         }
1465
1466         HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
1467         {
1468                 const int cchName = 256;
1469                 TCHAR szWindowName[cchName];
1470                 szWindowName[0] = 0;
1471                 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
1472                 HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
1473
1474                 T* pT = static_cast<T*>(this);
1475                 HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
1476
1477                 if(hWnd != NULL)
1478                         m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
1479
1480                 return hWnd;
1481         }
1482
1483         BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
1484         {
1485                 ATLASSERT(!::IsWindow(m_hWndToolBar));
1486                 if(nResourceID == 0)
1487                         nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
1488                 m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
1489                 return (m_hWndToolBar != NULL);
1490         }
1491
1492         virtual WNDPROC GetWindowProc()
1493         {
1494                 return MDIFrameWindowProc;
1495         }
1496
1497         static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1498         {
1499                 CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;
1500                 // set a ptr to this message and save the old value
1501 #if (_ATL_VER >= 0x0700)
1502                 ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
1503                 const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
1504 #else // !(_ATL_VER >= 0x0700)
1505                 MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
1506                 const MSG* pOldMsg = pThis->m_pCurrentMsg;
1507 #endif // !(_ATL_VER >= 0x0700)
1508                 pThis->m_pCurrentMsg = &msg;
1509                 // pass to the message map to process
1510                 LRESULT lRes = 0;
1511                 BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
1512                 // restore saved value for the current message
1513                 ATLASSERT(pThis->m_pCurrentMsg == &msg);
1514                 pThis->m_pCurrentMsg = pOldMsg;
1515                 // do the default processing if message was not handled
1516                 if(!bRet)
1517                 {
1518                         if(uMsg != WM_NCDESTROY)
1519                                 lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
1520                         else
1521                         {
1522                                 // unsubclass, if needed
1523                                 LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
1524                                 lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
1525                                 if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
1526                                         ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
1527 #if (_ATL_VER >= 0x0700)
1528                                 // mark window as destryed
1529                                 pThis->m_dwState |= WINSTATE_DESTROYED;
1530 #else // !(_ATL_VER >= 0x0700)
1531                                 // clear out window handle
1532                                 HWND hWnd = pThis->m_hWnd;
1533                                 pThis->m_hWnd = NULL;
1534                                 // clean up after window is destroyed
1535                                 pThis->OnFinalMessage(hWnd);
1536 #endif // !(_ATL_VER >= 0x0700)
1537                         }
1538                 }
1539 #if (_ATL_VER >= 0x0700)
1540                 if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL)
1541                 {
1542                         // clear out window handle
1543                         HWND hWnd = pThis->m_hWnd;
1544                         pThis->m_hWnd = NULL;
1545                         pThis->m_dwState &= ~WINSTATE_DESTROYED;
1546                         // clean up after window is destroyed
1547                         pThis->OnFinalMessage(hWnd);
1548                 }
1549 #endif // (_ATL_VER >= 0x0700)
1550                 return lRes;
1551         }
1552
1553         // Overriden to call DefWindowProc which uses DefFrameProc
1554         LRESULT DefWindowProc()
1555         {
1556                 const MSG* pMsg = m_pCurrentMsg;
1557                 LRESULT lRes = 0;
1558                 if (pMsg != NULL)
1559                         lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
1560                 return lRes;
1561         }
1562
1563         LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
1564         {
1565                 return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam);
1566         }
1567
1568         BOOL PreTranslateMessage(MSG* pMsg)
1569         {
1570                 if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))
1571                         return TRUE;
1572                 return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg);
1573         }
1574
1575         HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
1576         {
1577                 DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
1578                 DWORD dwExStyle = WS_EX_CLIENTEDGE;
1579
1580                 CLIENTCREATESTRUCT ccs = { 0 };
1581                 ccs.hWindowMenu = hWindowMenu;
1582                 ccs.idFirstChild = nFirstChildID;
1583
1584                 if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)
1585                 {
1586                         // parent MDI frame's scroll styles move to the MDICLIENT
1587                         dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL));
1588
1589                         // fast way to turn off the scrollbar bits (without a resize)
1590                         ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);
1591                 }
1592
1593                 // Create MDICLIENT window
1594                 m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL,
1595                         dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID),
1596                         ModuleHelper::GetModuleInstance(), (LPVOID)&ccs);
1597                 if (m_hWndClient == NULL)
1598                 {
1599                         ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n"));
1600                         return NULL;
1601                 }
1602
1603                 // Move it to the top of z-order
1604                 ::BringWindowToTop(m_hWndClient);
1605
1606                 // set as MDI client window
1607                 m_hWndMDIClient = m_hWndClient;
1608
1609                 // update to proper size
1610                 T* pT = static_cast<T*>(this);
1611                 pT->UpdateLayout();
1612
1613                 return m_hWndClient;
1614         }
1615
1616         typedef CFrameWindowImplBase<TBase, TWinTraits >   _baseClass;
1617
1618         BEGIN_MSG_MAP(CMDIFrameWindowImpl)
1619                 MESSAGE_HANDLER(WM_SIZE, OnSize)
1620                 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
1621                 MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
1622 #ifndef _ATL_NO_REBAR_SUPPORT
1623 #if (_WIN32_IE >= 0x0400)
1624                 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
1625 #endif // (_WIN32_IE >= 0x0400)
1626 #if (_WIN32_IE >= 0x0500)
1627                 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
1628 #endif // (_WIN32_IE >= 0x0500)
1629 #endif // !_ATL_NO_REBAR_SUPPORT
1630                 CHAIN_MSG_MAP(_baseClass)
1631         END_MSG_MAP()
1632
1633         LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1634         {
1635                 if(wParam != SIZE_MINIMIZED)
1636                 {
1637                         T* pT = static_cast<T*>(this);
1638                         pT->UpdateLayout();
1639                 }
1640                 // message must be handled, otherwise DefFrameProc would resize the client again
1641                 return 0;
1642         }
1643
1644         LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1645         {
1646                 // don't allow CFrameWindowImplBase to handle this one
1647                 return DefWindowProc(uMsg, wParam, lParam);
1648         }
1649
1650         LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1651         {
1652                 SetMDIFrameMenu();
1653                 return 0;
1654         }
1655
1656 #ifndef _ATL_NO_REBAR_SUPPORT
1657 #if (_WIN32_IE >= 0x0400)
1658         LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
1659         {
1660                 T* pT = static_cast<T*>(this);
1661                 pT->UpdateLayout(FALSE);
1662                 return 0;
1663         }
1664 #endif // (_WIN32_IE >= 0x0400)
1665
1666 #if (_WIN32_IE >= 0x0500)
1667         LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1668         {
1669                 T* pT = static_cast<T*>(this);
1670                 _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
1671                 if(!pT->PrepareChevronMenu(cmi))
1672                 {
1673                         bHandled = FALSE;
1674                         return 1;
1675                 }
1676                 // display a popup menu with hidden items
1677                 pT->DisplayChevronMenu(cmi);
1678                 // cleanup
1679                 pT->CleanupChevronMenu(cmi);
1680                 return 0;
1681         }
1682 #endif // (_WIN32_IE >= 0x0500)
1683 #endif // !_ATL_NO_REBAR_SUPPORT
1684 };
1685
1686 #endif // !_WIN32_WCE
1687
1688
1689 ///////////////////////////////////////////////////////////////////////////////
1690 // CMDIChildWindowImpl
1691
1692 #ifndef _WIN32_WCE
1693
1694 template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>
1695 class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
1696 {
1697 public:
1698         HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
1699                         DWORD dwStyle = 0, DWORD dwExStyle = 0,
1700                         UINT nMenuID = 0, LPVOID lpCreateParam = NULL)
1701         {
1702                 ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
1703
1704                 if(nMenuID != 0)
1705                         m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID));
1706
1707                 dwStyle = T::GetWndStyle(dwStyle);
1708                 dwExStyle = T::GetWndExStyle(dwExStyle);
1709
1710                 dwExStyle |= WS_EX_MDICHILD;   // force this one
1711                 m_pfnSuperWindowProc = ::DefMDIChildProc;
1712                 m_hWndMDIClient = hWndParent;
1713                 ATLASSERT(::IsWindow(m_hWndMDIClient));
1714
1715                 if(rect.m_lpRect == NULL)
1716                         rect.m_lpRect = &TBase::rcDefault;
1717
1718                 // If the currently active MDI child is maximized, we want to create this one maximized too
1719                 ATL::CWindow wndParent = hWndParent;
1720                 BOOL bMaximized = FALSE;
1721                 wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
1722                 if(bMaximized)
1723                         wndParent.SetRedraw(FALSE);
1724
1725                 HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);
1726
1727                 if(bMaximized)
1728                 {
1729                         // Maximize and redraw everything
1730                         if(hWnd != NULL)
1731                                 MDIMaximize(hWnd);
1732                         wndParent.SetRedraw(TRUE);
1733                         wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1734                         ::SetFocus(GetMDIFrame());   // focus will be set back to this window
1735                 }
1736                 else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
1737                 {
1738                         ::SetFocus(hWnd);
1739                 }
1740
1741                 return hWnd;
1742         }
1743
1744         HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
1745         {
1746                 const int cchName = 256;
1747                 TCHAR szWindowName[cchName];
1748                 szWindowName[0] = 0;
1749                 if(lpcstrWindowName == NULL)
1750                 {
1751                         ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
1752                         lpcstrWindowName = szWindowName;
1753                 }
1754
1755                 T* pT = static_cast<T*>(this);
1756                 HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);
1757
1758                 if(hWnd != NULL)
1759                         m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
1760
1761                 return hWnd;
1762         }
1763
1764         BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
1765         {
1766                 ATLASSERT(!::IsWindow(m_hWndToolBar));
1767                 if(nResourceID == 0)
1768                         nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
1769                 m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
1770                 return (m_hWndToolBar != NULL);
1771         }
1772
1773         BOOL UpdateClientEdge(LPRECT lpRect = NULL)
1774         {
1775                 // only adjust for active MDI child window
1776                 HWND hWndChild = MDIGetActive();
1777                 if(hWndChild != NULL && hWndChild != m_hWnd)
1778                         return FALSE;
1779
1780                 // need to adjust the client edge style as max/restore happens
1781                 DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE);
1782                 DWORD dwNewStyle = dwStyle;
1783                 if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0))
1784                         dwNewStyle &= ~(WS_EX_CLIENTEDGE);
1785                 else
1786                         dwNewStyle |= WS_EX_CLIENTEDGE;
1787
1788                 if(dwStyle != dwNewStyle)
1789                 {
1790                         // SetWindowPos will not move invalid bits
1791                         ::RedrawWindow(m_hWndMDIClient, NULL, NULL,
1792                                 RDW_INVALIDATE | RDW_ALLCHILDREN);
1793                         // remove/add WS_EX_CLIENTEDGE to MDI client area
1794                         ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
1795                         ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0,
1796                                 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
1797                                 SWP_NOZORDER | SWP_NOCOPYBITS);
1798
1799                         // return new client area
1800                         if (lpRect != NULL)
1801                                 ::GetClientRect(m_hWndMDIClient, lpRect);
1802
1803                         return TRUE;
1804                 }
1805
1806                 return FALSE;
1807         }
1808
1809         typedef CFrameWindowImplBase<TBase, TWinTraits >   _baseClass;
1810         BEGIN_MSG_MAP(CMDIChildWindowImpl)
1811                 MESSAGE_HANDLER(WM_SIZE, OnSize)
1812                 MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
1813                 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
1814                 MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
1815                 MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
1816                 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
1817 #ifndef _ATL_NO_REBAR_SUPPORT
1818 #if (_WIN32_IE >= 0x0400)
1819                 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
1820 #endif // (_WIN32_IE >= 0x0400)
1821 #if (_WIN32_IE >= 0x0500)
1822                 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
1823 #endif // (_WIN32_IE >= 0x0500)
1824 #endif // !_ATL_NO_REBAR_SUPPORT
1825                 CHAIN_MSG_MAP(_baseClass)
1826         END_MSG_MAP()
1827
1828         LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1829         {
1830                 DefWindowProc(uMsg, wParam, lParam);   // needed for MDI children
1831                 if(wParam != SIZE_MINIMIZED)
1832                 {
1833                         T* pT = static_cast<T*>(this);
1834                         pT->UpdateLayout();
1835                 }
1836                 return 0;
1837         }
1838
1839         LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1840         {
1841                 // update MDI client edge and adjust MDI child rect
1842                 LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;
1843
1844                 if(!(lpWndPos->flags & SWP_NOSIZE))
1845                 {
1846                         RECT rectClient;
1847                         if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0))
1848                         {
1849                                 ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle());
1850                                 lpWndPos->x = rectClient.left;
1851                                 lpWndPos->y = rectClient.top;
1852                                 lpWndPos->cx = rectClient.right - rectClient.left;
1853                                 lpWndPos->cy = rectClient.bottom - rectClient.top;
1854                         }
1855                 }
1856
1857                 bHandled = FALSE;
1858                 return 1;
1859         }
1860
1861         LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1862         {
1863                 LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
1864
1865                 // Activate this MDI window if needed
1866                 if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT)
1867                 {
1868                         if(MDIGetActive() != m_hWnd)
1869                                 MDIActivate(m_hWnd);
1870                 }
1871
1872                 return lRes;
1873         }
1874
1875         LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1876         {
1877                 return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam);
1878         }
1879
1880         LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1881         {
1882                 if((HWND)lParam == m_hWnd && m_hMenu != NULL)
1883                         SetMDIFrameMenu();
1884                 else if((HWND)lParam == NULL)
1885                         ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0);
1886
1887                 bHandled = FALSE;
1888                 return 1;
1889         }
1890
1891         LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1892         {
1893                 if(m_hMenu != NULL)
1894                 {
1895                         ::DestroyMenu(m_hMenu);
1896                         m_hMenu = NULL;
1897                 }
1898                 UpdateClientEdge();
1899                 bHandled = FALSE;
1900                 return 1;
1901         }
1902
1903 #ifndef _ATL_NO_REBAR_SUPPORT
1904 #if (_WIN32_IE >= 0x0400)
1905         LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
1906         {
1907                 T* pT = static_cast<T*>(this);
1908                 pT->UpdateLayout(FALSE);
1909                 return 0;
1910         }
1911 #endif // (_WIN32_IE >= 0x0400)
1912
1913 #if (_WIN32_IE >= 0x0500)
1914         LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1915         {
1916                 T* pT = static_cast<T*>(this);
1917                 _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
1918                 if(!pT->PrepareChevronMenu(cmi))
1919                 {
1920                         bHandled = FALSE;
1921                         return 1;
1922                 }
1923                 // display a popup menu with hidden items
1924                 pT->DisplayChevronMenu(cmi);
1925                 // cleanup
1926                 pT->CleanupChevronMenu(cmi);
1927                 return 0;
1928         }
1929 #endif // (_WIN32_IE >= 0x0500)
1930 #endif // !_ATL_NO_REBAR_SUPPORT
1931 };
1932
1933 #endif // !_WIN32_WCE
1934
1935
1936 ///////////////////////////////////////////////////////////////////////////////
1937 // COwnerDraw - MI class for owner-draw support
1938
1939 template <class T>
1940 class COwnerDraw
1941 {
1942 public:
1943 #if (_ATL_VER < 0x0700)
1944         BOOL m_bHandledOD;
1945
1946         BOOL IsMsgHandled() const
1947         {
1948                 return m_bHandledOD;
1949         }
1950         void SetMsgHandled(BOOL bHandled)
1951         {
1952                 m_bHandledOD = bHandled;
1953         }
1954 #endif // (_ATL_VER < 0x0700)
1955
1956 // Message map and handlers
1957         BEGIN_MSG_MAP(COwnerDraw< T >)
1958                 MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
1959                 MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
1960                 MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
1961                 MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
1962         ALT_MSG_MAP(1)
1963                 MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
1964                 MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
1965                 MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
1966                 MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
1967         END_MSG_MAP()
1968
1969         LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1970         {
1971                 T* pT = static_cast<T*>(this);
1972                 pT->SetMsgHandled(TRUE);
1973                 pT->DrawItem((LPDRAWITEMSTRUCT)lParam);
1974                 bHandled = pT->IsMsgHandled();
1975                 return (LRESULT)TRUE;
1976         }
1977
1978         LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1979         {
1980                 T* pT = static_cast<T*>(this);
1981                 pT->SetMsgHandled(TRUE);
1982                 pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);
1983                 bHandled = pT->IsMsgHandled();
1984                 return (LRESULT)TRUE;
1985         }
1986
1987         LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1988         {
1989                 T* pT = static_cast<T*>(this);
1990                 pT->SetMsgHandled(TRUE);
1991                 bHandled = pT->IsMsgHandled();
1992                 return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);
1993         }
1994
1995         LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1996         {
1997                 T* pT = static_cast<T*>(this);
1998                 pT->SetMsgHandled(TRUE);
1999                 pT->DeleteItem((LPDELETEITEMSTRUCT)lParam);
2000                 bHandled = pT->IsMsgHandled();
2001                 return (LRESULT)TRUE;
2002         }
2003
2004 // Overrideables
2005         void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
2006         {
2007                 // must be implemented
2008                 ATLASSERT(FALSE);
2009         }
2010
2011         void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
2012         {
2013                 if(lpMeasureItemStruct->CtlType != ODT_MENU)
2014                 {
2015                         // return default height for a system font
2016                         T* pT = static_cast<T*>(this);
2017                         HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);
2018                         CClientDC dc(hWnd);
2019                         TEXTMETRIC tm = { 0 };
2020                         dc.GetTextMetrics(&tm);
2021
2022                         lpMeasureItemStruct->itemHeight = tm.tmHeight;
2023                 }
2024                 else
2025                         lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);
2026         }
2027
2028         int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)
2029         {
2030                 // all items are equal
2031                 return 0;
2032         }
2033
2034         void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
2035         {
2036                 // default - nothing
2037         }
2038 };
2039
2040
2041 ///////////////////////////////////////////////////////////////////////////////
2042 // Update UI macros
2043
2044 // these build the Update UI map inside a class definition
2045 #define BEGIN_UPDATE_UI_MAP(thisClass) \
2046         static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \
2047         { \
2048                 static const _AtlUpdateUIMap theMap[] = \
2049                 {
2050
2051 #define UPDATE_ELEMENT(nID, wType) \
2052                         { nID,  wType },
2053
2054 #define END_UPDATE_UI_MAP() \
2055                         { (WORD)-1, 0 } \
2056                 }; \
2057                 return theMap; \
2058         }
2059
2060 ///////////////////////////////////////////////////////////////////////////////
2061 // CUpdateUI - manages UI elements updating
2062
2063 class CUpdateUIBase
2064 {
2065 public:
2066         // constants
2067         enum
2068         {
2069                 // UI element type
2070                 UPDUI_MENUPOPUP         = 0x0001,
2071                 UPDUI_MENUBAR           = 0x0002,
2072                 UPDUI_CHILDWINDOW       = 0x0004,
2073                 UPDUI_TOOLBAR           = 0x0008,
2074                 UPDUI_STATUSBAR         = 0x0010,
2075                 // state
2076                 UPDUI_ENABLED           = 0x0000,
2077                 UPDUI_DISABLED          = 0x0100,
2078                 UPDUI_CHECKED           = 0x0200,
2079                 UPDUI_CHECKED2          = 0x0400,
2080                 UPDUI_RADIO             = 0x0800,
2081                 UPDUI_DEFAULT           = 0x1000,
2082                 UPDUI_TEXT              = 0x2000,
2083                 // internal state
2084                 UPDUI_CLEARDEFAULT      = 0x4000,
2085         };
2086
2087         // element data
2088         struct _AtlUpdateUIElement
2089         {
2090                 HWND m_hWnd;
2091                 WORD m_wType;
2092
2093                 bool operator ==(const _AtlUpdateUIElement& e) const
2094                 { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); }
2095         };
2096
2097         // map data
2098         struct _AtlUpdateUIMap
2099         {
2100                 WORD m_nID;
2101                 WORD m_wType;
2102
2103                 bool operator ==(const _AtlUpdateUIMap& e) const
2104                 { return (m_nID == e.m_nID && m_wType == e.m_wType); }
2105         };
2106
2107         // instance data
2108         struct _AtlUpdateUIData
2109         {
2110                 WORD m_wState;
2111                 union
2112                 {
2113                         void* m_lpData;
2114                         LPTSTR m_lpstrText;
2115                 };
2116
2117                 bool operator ==(const _AtlUpdateUIData& e) const
2118                 { return (m_wState == e.m_wState && m_lpData == e.m_lpData); }
2119         };
2120
2121         ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements;   // elements data
2122         const _AtlUpdateUIMap* m_pUIMap;                       // static UI data
2123         _AtlUpdateUIData* m_pUIData;                           // instance UI data
2124         WORD m_wDirtyType;                                     // global dirty flag
2125
2126         bool m_bBlockAccelerators;
2127
2128
2129 // Constructor, destructor
2130         CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)
2131         { }
2132
2133         ~CUpdateUIBase()
2134         {
2135                 if(m_pUIMap != NULL && m_pUIData != NULL)
2136                 {
2137                         const _AtlUpdateUIMap* pUIMap = m_pUIMap;
2138                         _AtlUpdateUIData* pUIData = m_pUIData;
2139                         while(pUIMap->m_nID != (WORD)-1)
2140                         {
2141                                 if(pUIData->m_wState & UPDUI_TEXT)
2142                                         delete [] pUIData->m_lpstrText;
2143                                 pUIMap++;
2144                                 pUIData++;
2145                         }
2146                         delete [] m_pUIData;
2147                 }
2148         }
2149
2150 // Check for disabled commands
2151         bool UIGetBlockAccelerators() const
2152         {
2153                 return m_bBlockAccelerators;
2154         }
2155
2156         bool UISetBlockAccelerators(bool bBlock)
2157         {
2158                 bool bOld = m_bBlockAccelerators;
2159                 m_bBlockAccelerators = bBlock;
2160                 return bOld;
2161         }
2162
2163 // Add elements
2164         BOOL UIAddMenuBar(HWND hWnd)                // menu bar (main menu)
2165         {
2166                 if(hWnd == NULL)
2167                         return FALSE;
2168                 _AtlUpdateUIElement e;
2169                 e.m_hWnd = hWnd;
2170                 e.m_wType = UPDUI_MENUBAR;
2171                 return m_UIElements.Add(e);
2172         }
2173
2174         BOOL UIAddToolBar(HWND hWnd)                // toolbar
2175         {
2176                 if(hWnd == NULL)
2177                         return FALSE;
2178                 _AtlUpdateUIElement e;
2179                 e.m_hWnd = hWnd;
2180                 e.m_wType = UPDUI_TOOLBAR;
2181                 return m_UIElements.Add(e);
2182         }
2183
2184         BOOL UIAddStatusBar(HWND hWnd)              // status bar
2185         {
2186                 if(hWnd == NULL)
2187                         return FALSE;
2188                 _AtlUpdateUIElement e;
2189                 e.m_hWnd = hWnd;
2190                 e.m_wType = UPDUI_STATUSBAR;
2191                 return m_UIElements.Add(e);
2192         }
2193
2194         BOOL UIAddChildWindowContainer(HWND hWnd)   // child window
2195         {
2196                 if(hWnd == NULL)
2197                         return FALSE;
2198                 _AtlUpdateUIElement e;
2199                 e.m_hWnd = hWnd;
2200                 e.m_wType = UPDUI_CHILDWINDOW;
2201                 return m_UIElements.Add(e);
2202         }
2203
2204 // Message map for popup menu updates and accelerator blocking
2205         BEGIN_MSG_MAP(CUpdateUIBase)
2206                 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
2207                 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
2208         END_MSG_MAP()
2209
2210         LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
2211         {
2212                 bHandled = FALSE;
2213                 HMENU hMenu = (HMENU)wParam;
2214                 if(hMenu == NULL)
2215                         return 1;
2216                 _AtlUpdateUIData* pUIData = m_pUIData;
2217                 if(pUIData == NULL)
2218                         return 1;
2219                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2220                 while(pMap->m_nID != (WORD)-1)
2221                 {
2222                         if(pMap->m_wType & UPDUI_MENUPOPUP)
2223                                 UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
2224                         pMap++;
2225                         pUIData++;
2226                 }
2227                 return 0;
2228         }
2229
2230         LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
2231         {
2232                 bHandled = FALSE;
2233                 if(m_bBlockAccelerators && HIWORD(wParam) == 1)   // accelerators only
2234                 {
2235                         int nID = LOWORD(wParam);
2236                         if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)
2237                         {
2238                                 ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID);
2239                                 bHandled = TRUE;   // eat the command, UI item is disabled
2240                         }
2241                 }
2242                 return 0;
2243         }
2244
2245 // methods for setting UI element state
2246         BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
2247         {
2248                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2249                 _AtlUpdateUIData* pUIData = m_pUIData;
2250                 if(pUIData == NULL)
2251                         return FALSE;
2252
2253                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2254                 {
2255                         if(nID == (int)pMap->m_nID)
2256                         {
2257                                 if(bEnable)
2258                                 {
2259                                         if(pUIData->m_wState & UPDUI_DISABLED)
2260                                         {
2261                                                 pUIData->m_wState |= pMap->m_wType;
2262                                                 pUIData->m_wState &= ~UPDUI_DISABLED;
2263                                         }
2264                                 }
2265                                 else
2266                                 {
2267                                         if(!(pUIData->m_wState & UPDUI_DISABLED))
2268                                         {
2269                                                 pUIData->m_wState |= pMap->m_wType;
2270                                                 pUIData->m_wState |= UPDUI_DISABLED;
2271                                         }
2272                                 }
2273
2274                                 if(bForceUpdate)
2275                                         pUIData->m_wState |= pMap->m_wType;
2276                                 if(pUIData->m_wState & pMap->m_wType)
2277                                         m_wDirtyType |= pMap->m_wType;
2278
2279                                 break;   // found
2280                         }
2281                 }
2282
2283                 return TRUE;
2284         }
2285
2286         BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)
2287         {
2288                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2289                 _AtlUpdateUIData* pUIData = m_pUIData;
2290                 if(pUIData == NULL)
2291                         return FALSE;
2292
2293                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2294                 {
2295                         if(nID == (int)pMap->m_nID)
2296                         {
2297                                 switch(nCheck)
2298                                 {
2299                                 case 0:
2300                                         if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))
2301                                         {
2302                                                 pUIData->m_wState |= pMap->m_wType;
2303                                                 pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);
2304                                         }
2305                                         break;
2306                                 case 1:
2307                                         if(!(pUIData->m_wState & UPDUI_CHECKED))
2308                                         {
2309                                                 pUIData->m_wState |= pMap->m_wType;
2310                                                 pUIData->m_wState &= ~UPDUI_CHECKED2;
2311                                                 pUIData->m_wState |= UPDUI_CHECKED;
2312                                         }
2313                                         break;
2314                                 case 2:
2315                                         if(!(pUIData->m_wState & UPDUI_CHECKED2))
2316                                         {
2317                                                 pUIData->m_wState |= pMap->m_wType;
2318                                                 pUIData->m_wState &= ~UPDUI_CHECKED;
2319                                                 pUIData->m_wState |= UPDUI_CHECKED2;
2320                                         }
2321                                         break;
2322                                 }
2323
2324                                 if(bForceUpdate)
2325                                         pUIData->m_wState |= pMap->m_wType;
2326                                 if(pUIData->m_wState & pMap->m_wType)
2327                                         m_wDirtyType |= pMap->m_wType;
2328
2329                                 break;   // found
2330                         }
2331                 }
2332
2333                 return TRUE;
2334         }
2335
2336         // variant that supports bool (checked/not-checked, no intermediate state)
2337         BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
2338         {
2339                 return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate);
2340         }
2341
2342         BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)
2343         {
2344                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2345                 _AtlUpdateUIData* pUIData = m_pUIData;
2346                 if(pUIData == NULL)
2347                         return FALSE;
2348
2349                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2350                 {
2351                         if(nID == (int)pMap->m_nID)
2352                         {
2353                                 if(bRadio)
2354                                 {
2355                                         if(!(pUIData->m_wState & UPDUI_RADIO))
2356                                         {
2357                                                 pUIData->m_wState |= pMap->m_wType;
2358                                                 pUIData->m_wState |= UPDUI_RADIO;
2359                                         }
2360                                 }
2361                                 else
2362                                 {
2363                                         if(pUIData->m_wState & UPDUI_RADIO)
2364                                         {
2365                                                 pUIData->m_wState |= pMap->m_wType;
2366                                                 pUIData->m_wState &= ~UPDUI_RADIO;
2367                                         }
2368                                 }
2369
2370                                 if(bForceUpdate)
2371                                         pUIData->m_wState |= pMap->m_wType;
2372                                 if(pUIData->m_wState & pMap->m_wType)
2373                                         m_wDirtyType |= pMap->m_wType;
2374
2375                                 break;   // found
2376                         }
2377                 }
2378
2379                 return TRUE;
2380         }
2381
2382         BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)
2383         {
2384                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2385                 _AtlUpdateUIData* pUIData = m_pUIData;
2386                 if(pUIData == NULL)
2387                         return FALSE;
2388                 if(lpstrText == NULL)
2389                         lpstrText = _T("");
2390
2391                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2392                 {
2393                         if(nID == (int)pMap->m_nID)
2394                         {
2395                                 if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText))
2396                                 {
2397                                         delete [] pUIData->m_lpstrText;
2398                                         pUIData->m_lpstrText = NULL;
2399                                         int nStrLen = lstrlen(lpstrText);
2400                                         ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]);
2401                                         if(pUIData->m_lpstrText == NULL)
2402                                         {
2403                                                 ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n"));
2404                                                 break;
2405                                         }
2406                                         SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText);
2407                                         pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
2408                                 }
2409
2410                                 if(bForceUpdate)
2411                                         pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
2412                                 if(pUIData->m_wState & pMap->m_wType)
2413                                         m_wDirtyType |= pMap->m_wType;
2414
2415                                 break;   // found
2416                         }
2417                 }
2418
2419                 return TRUE;
2420         }
2421
2422         BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE)
2423         {
2424                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2425                 _AtlUpdateUIData* pUIData = m_pUIData;
2426                 if(pUIData == NULL)
2427                         return FALSE;
2428
2429                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2430                 {
2431                         if(nID == (int)pMap->m_nID)
2432                         {
2433                                 if(bDefault)
2434                                 {
2435                                         if((pUIData->m_wState & UPDUI_DEFAULT) == 0)
2436                                         {
2437                                                 pUIData->m_wState |= pMap->m_wType;
2438                                                 pUIData->m_wState |= UPDUI_DEFAULT;
2439                                         }
2440                                 }
2441                                 else
2442                                 {
2443                                         if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
2444                                         {
2445                                                 pUIData->m_wState |= pMap->m_wType;
2446                                                 pUIData->m_wState &= ~UPDUI_DEFAULT;
2447                                                 pUIData->m_wState |= UPDUI_CLEARDEFAULT;
2448                                         }
2449                                 }
2450
2451                                 if(bForceUpdate)
2452                                         pUIData->m_wState |= pMap->m_wType;
2453                                 if(pUIData->m_wState & pMap->m_wType)
2454                                         m_wDirtyType |= pMap->m_wType;
2455
2456                                 break;   // found
2457                         }
2458                 }
2459
2460                 return TRUE;
2461         }
2462
2463 // methods for complete state set/get
2464         BOOL UISetState(int nID, DWORD dwState)
2465         {
2466                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2467                 _AtlUpdateUIData* pUIData = m_pUIData;
2468                 if(pUIData == NULL)
2469                         return FALSE;
2470                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2471                 {
2472                         if(nID == (int)pMap->m_nID)
2473                         {               
2474                                 pUIData->m_wState = (WORD)(dwState | pMap->m_wType);
2475                                 m_wDirtyType |= pMap->m_wType;
2476                                 break;   // found
2477                         }
2478                 }
2479                 return TRUE;
2480         }
2481
2482         DWORD UIGetState(int nID)
2483         {
2484                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2485                 _AtlUpdateUIData* pUIData = m_pUIData;
2486                 if(pUIData == NULL)
2487                         return 0;
2488                 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
2489                 {
2490                         if(nID == (int)pMap->m_nID)
2491                                 return pUIData->m_wState;
2492                 }
2493                 return 0;
2494         }
2495
2496 // methods for updating UI
2497 #ifndef _WIN32_WCE
2498         BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)
2499         {
2500                 if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)
2501                         return TRUE;
2502
2503                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2504                 _AtlUpdateUIData* pUIData = m_pUIData;
2505                 if(pUIData == NULL)
2506                         return FALSE;
2507
2508                 while(pMap->m_nID != (WORD)-1)
2509                 {
2510                         for(int i = 0; i < m_UIElements.GetSize(); i++)
2511                         {
2512                                 if(m_UIElements[i].m_wType == UPDUI_MENUBAR)
2513                                 {
2514                                         HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);
2515                                         if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))
2516                                                 UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
2517                                 }
2518                                 if(bMainMenu)
2519                                         ::DrawMenuBar(m_UIElements[i].m_hWnd);
2520                         }
2521                         pMap++;
2522                         pUIData->m_wState &= ~UPDUI_MENUBAR;
2523                         if(pUIData->m_wState & UPDUI_TEXT)
2524                         {
2525                                 delete [] pUIData->m_lpstrText;
2526                                 pUIData->m_lpstrText = NULL;
2527                                 pUIData->m_wState &= ~UPDUI_TEXT;
2528                         }
2529                         pUIData++;
2530                 }
2531
2532                 m_wDirtyType &= ~UPDUI_MENUBAR;
2533                 return TRUE;
2534         }
2535 #endif // !_WIN32_WCE
2536
2537         BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)
2538         {
2539                 if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)
2540                         return TRUE;
2541
2542                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2543                 _AtlUpdateUIData* pUIData = m_pUIData;
2544                 if(pUIData == NULL)
2545                         return FALSE;
2546
2547                 while(pMap->m_nID != (WORD)-1)
2548                 {
2549                         for(int i = 0; i < m_UIElements.GetSize(); i++)
2550                         {
2551                                 if(m_UIElements[i].m_wType == UPDUI_TOOLBAR)
2552                                 {
2553                                         if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))
2554                                                 UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
2555                                 }
2556                         }
2557                         pMap++;
2558                         pUIData->m_wState &= ~UPDUI_TOOLBAR;
2559                         pUIData++;
2560                 }
2561
2562                 m_wDirtyType &= ~UPDUI_TOOLBAR;
2563                 return TRUE;
2564         }
2565
2566         BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
2567         {
2568                 if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
2569                         return TRUE;
2570
2571                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2572                 _AtlUpdateUIData* pUIData = m_pUIData;
2573                 if(pUIData == NULL)
2574                         return FALSE;
2575
2576                 while(pMap->m_nID != (WORD)-1)
2577                 {
2578                         for(int i = 0; i < m_UIElements.GetSize(); i++)
2579                         {
2580                                 if(m_UIElements[i].m_wType == UPDUI_STATUSBAR)
2581                                 {
2582                                         if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))
2583                                                 UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
2584                                 }
2585                         }
2586                         pMap++;
2587                         pUIData->m_wState &= ~UPDUI_STATUSBAR;
2588                         if(pUIData->m_wState & UPDUI_TEXT)
2589                         {
2590                                 delete [] pUIData->m_lpstrText;
2591                                 pUIData->m_lpstrText = NULL;
2592                                 pUIData->m_wState &= ~UPDUI_TEXT;
2593                         }
2594                         pUIData++;
2595                 }
2596
2597                 m_wDirtyType &= ~UPDUI_STATUSBAR;
2598                 return TRUE;
2599         }
2600
2601         BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
2602         {
2603                 if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
2604                         return TRUE;
2605
2606                 const _AtlUpdateUIMap* pMap = m_pUIMap;
2607                 _AtlUpdateUIData* pUIData = m_pUIData;
2608                 if(pUIData == NULL)
2609                         return FALSE;
2610
2611                 while(pMap->m_nID != (WORD)-1)
2612                 {
2613                         for(int i = 0; i < m_UIElements.GetSize(); i++)
2614                         {
2615                                 if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
2616                                 {
2617                                         if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
2618                                                 UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
2619                                 }
2620                         }
2621                         pMap++;
2622                         pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
2623                         if(pUIData->m_wState & UPDUI_TEXT)
2624                         {
2625                                 delete [] pUIData->m_lpstrText;
2626                                 pUIData->m_lpstrText = NULL;
2627                                 pUIData->m_wState &= ~UPDUI_TEXT;
2628                         }
2629                         pUIData++;
2630                 }
2631
2632                 m_wDirtyType &= ~UPDUI_CHILDWINDOW;
2633                 return TRUE;
2634         }
2635
2636 // internal element specific methods
2637         static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)
2638         {
2639 #ifndef _WIN32_WCE
2640                 if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0)
2641                 {
2642                         ::SetMenuDefaultItem(hMenu, (UINT)-1, 0);
2643                         pUIData->m_wState &= ~UPDUI_CLEARDEFAULT;
2644                 }
2645 #endif // !_WIN32_WCE
2646
2647                 CMenuItemInfo mii;
2648                 mii.fMask = MIIM_STATE;
2649                 mii.wID = nID;
2650
2651 #ifndef _WIN32_WCE
2652                 if((pUIData->m_wState & UPDUI_DISABLED) != 0)
2653                         mii.fState |= MFS_DISABLED | MFS_GRAYED;
2654                 else
2655                         mii.fState |= MFS_ENABLED;
2656
2657                 if((pUIData->m_wState & UPDUI_CHECKED) != 0)
2658                         mii.fState |= MFS_CHECKED;
2659                 else
2660                         mii.fState |= MFS_UNCHECKED;
2661
2662                 if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
2663                         mii.fState |= MFS_DEFAULT;
2664 #else // CE specific
2665                 // ::SetMenuItemInfo() can't disable or check menu items
2666                 // on Windows CE, so we have to do that directly
2667                 UINT uEnable = MF_BYCOMMAND;
2668                 if((pUIData->m_wState & UPDUI_DISABLED) != 0)
2669                         uEnable |= MF_GRAYED;
2670                 else
2671                         uEnable |= MF_ENABLED;
2672                 ::EnableMenuItem(hMenu, nID, uEnable);
2673
2674                 UINT uCheck = MF_BYCOMMAND;
2675                 if((pUIData->m_wState & UPDUI_CHECKED) != 0)
2676                         uCheck |= MF_CHECKED;
2677                 else
2678                         uCheck |= MF_UNCHECKED;
2679                 ::CheckMenuItem(hMenu, nID, uCheck);
2680 #endif // _WIN32_WCE
2681
2682                 if((pUIData->m_wState & UPDUI_TEXT) != 0)
2683                 {
2684                         CMenuItemInfo miiNow;
2685                         miiNow.fMask = MIIM_TYPE;
2686                         miiNow.wID = nID;
2687                         if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow))
2688                         {
2689                                 mii.fMask |= MIIM_TYPE;
2690                                 // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING
2691 #ifndef _WIN32_WCE
2692                                 mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING;
2693 #else // CE specific
2694                                 mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING;
2695 #endif // _WIN32_WCE
2696                                 mii.dwTypeData = pUIData->m_lpstrText;
2697                         }
2698                 }
2699
2700                 ::SetMenuItemInfo(hMenu, nID, FALSE, &mii);
2701         }
2702
2703         static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)
2704         {
2705                 // Note: only handles enabled/disabled, checked state, and radio (press)
2706                 ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
2707                 ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);
2708                 ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);
2709                 ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);
2710         }
2711
2712         static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)
2713         {
2714                 // Note: only handles text
2715                 if(pUIData->m_wState & UPDUI_TEXT)
2716                         ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText);
2717         }
2718
2719         static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)
2720         {
2721                 HWND hChild = ::GetDlgItem(hWnd, nID);
2722
2723                 ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
2724                 // for check and radio, assume that window is a button
2725                 int nCheck = BST_UNCHECKED;
2726                 if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO)
2727                         nCheck = BST_CHECKED;
2728                 else if(pUIData->m_wState & UPDUI_CHECKED2)
2729                         nCheck = BST_INDETERMINATE;
2730                 ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);
2731                 if(pUIData->m_wState & UPDUI_DEFAULT)
2732                 {
2733                         DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);
2734                         if(HIWORD(dwRet) == DC_HASDEFID)
2735                         {
2736                                 HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));
2737                                 // remove BS_DEFPUSHBUTTON
2738                                 ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
2739                         }
2740                         ::SendMessage(hWnd, DM_SETDEFID, nID, 0L);
2741                 }
2742                 if(pUIData->m_wState & UPDUI_TEXT)
2743                         ::SetWindowText(hChild, pUIData->m_lpstrText);
2744         }
2745 };
2746
2747 template <class T>
2748 class CUpdateUI : public CUpdateUIBase
2749 {
2750 public:
2751         CUpdateUI()
2752         {
2753                 T* pT = static_cast<T*>(this);
2754                 pT;
2755                 const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
2756                 m_pUIMap = pMap;
2757                 ATLASSERT(m_pUIMap != NULL);
2758                 int nCount;
2759                 for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++)
2760                         pMap++;
2761
2762                 // check for duplicates (debug only)
2763 #ifdef _DEBUG
2764                 for(int i = 0; i < nCount; i++)
2765                 {
2766                         for(int j = 0; j < nCount; j++)
2767                         {
2768                                 // shouldn't have duplicates in the update UI map
2769                                 if(i != j)
2770                                         ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);
2771                         }
2772                 }
2773 #endif // _DEBUG
2774
2775                 ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);
2776                 ATLASSERT(m_pUIData != NULL);
2777
2778                 if(m_pUIData != NULL)
2779                         memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);
2780         }
2781 };
2782
2783
2784 ///////////////////////////////////////////////////////////////////////////////
2785 // CDynamicUpdateUI - allows update elements to dynamically added and removed
2786 //                    in addition to a static update UI map
2787
2788 template <class T>
2789 class CDynamicUpdateUI : public CUpdateUIBase
2790 {
2791 public:
2792 // Data members
2793         ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap;     // copy of the static UI data
2794         ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData;   // instance UI data
2795
2796 // Constructor/destructor
2797         CDynamicUpdateUI()
2798         {
2799                 T* pT = static_cast<T*>(this);
2800                 pT;
2801                 const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
2802                 ATLASSERT(pMap != NULL);
2803
2804                 for(;;)
2805                 {
2806                         BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap);
2807                         ATLASSERT(bRet);
2808
2809                         if(bRet != FALSE)
2810                         {
2811                                 _AtlUpdateUIData data = { 0, NULL };
2812                                 bRet = m_arrUIData.Add(data);
2813                                 ATLASSERT(bRet);
2814                         }
2815
2816                         if(pMap->m_nID == (WORD)-1)
2817                                 break;
2818
2819                         pMap++;
2820                 }
2821
2822                 ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize());
2823
2824 #ifdef _DEBUG
2825                 // check for duplicates (debug only)
2826                 for(int i = 0; i < m_arrUIMap.GetSize(); i++)
2827                 {
2828                         for(int j = 0; j < m_arrUIMap.GetSize(); j++)
2829                         {
2830                                 // shouldn't have duplicates in the update UI map
2831                                 if(i != j)
2832                                         ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID);
2833                         }
2834                 }
2835 #endif // _DEBUG
2836
2837                 // Set internal data pointers to point to the new data arrays
2838                 m_pUIMap = m_arrUIMap.m_aT;
2839                 m_pUIData = m_arrUIData.m_aT;
2840         }
2841
2842         ~CDynamicUpdateUI()
2843         {
2844                 for(int i = 0; i < m_arrUIData.GetSize(); i++)
2845                 {
2846                         if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)
2847                                 delete [] m_arrUIData[i].m_lpstrText;
2848                 }
2849
2850                 // Reset internal data pointers (memory will be released by CSimpleArray d-tor)
2851                 m_pUIMap = NULL;
2852                 m_pUIData = NULL;
2853         }
2854
2855 // Methods for dynamically adding and removing update elements
2856         bool UIAddUpdateElement(WORD nID, WORD wType)
2857         {
2858                 // check for duplicates
2859                 for(int i = 0; i < m_arrUIMap.GetSize(); i++)
2860                 {
2861                         // shouldn't have duplicates in the update UI map
2862                         ATLASSERT(m_arrUIMap[i].m_nID != nID);
2863                         if(m_arrUIMap[i].m_nID == nID)
2864                                 return false;
2865                 }
2866
2867                 bool bRetVal = false;
2868
2869                 // Add new end element
2870                 _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 };
2871                 BOOL bRet = m_arrUIMap.Add(uumEnd);
2872                 ATLASSERT(bRet);
2873
2874                 if(bRet != FALSE)
2875                 {
2876                         _AtlUpdateUIData uud = { 0, NULL };
2877                         bRet = m_arrUIData.Add(uud);
2878                         ATLASSERT(bRet);
2879
2880                         // Set new data to the previous end element
2881                         if(bRet != FALSE)
2882                         {
2883                                 int nSize = m_arrUIMap.GetSize();
2884                                 _AtlUpdateUIMap uum = { nID, wType };
2885                                 m_arrUIMap.SetAtIndex(nSize - 2, uum);
2886                                 m_arrUIData.SetAtIndex(nSize - 2, uud);
2887
2888                                 // Set internal data pointers again, just in case that memory moved
2889                                 m_pUIMap = m_arrUIMap.m_aT;
2890                                 m_pUIData = m_arrUIData.m_aT;
2891
2892                                 bRetVal = true;
2893                         }
2894                 }
2895
2896                 return bRetVal;
2897         }
2898
2899         bool UIRemoveUpdateElement(WORD nID)
2900         {
2901                 bool bRetVal = false;
2902
2903                 for(int i = 0; i < m_arrUIMap.GetSize(); i++)
2904                 {
2905                         if(m_arrUIMap[i].m_nID == nID)
2906                         {
2907                                 BOOL bRet = m_arrUIMap.RemoveAt(i);
2908                                 ATLASSERT(bRet);
2909                                 bRet = m_arrUIData.RemoveAt(i);
2910                                 ATLASSERT(bRet);
2911
2912                                 bRetVal = true;
2913                                 break;
2914                         }
2915                 }
2916
2917                 return bRetVal;
2918         }
2919 };
2920
2921
2922 ///////////////////////////////////////////////////////////////////////////////
2923 // CDialogResize - provides support for resizing dialog controls
2924 //                 (works for any window that has child controls)
2925
2926 // Put CDialogResize in the list of base classes for a dialog (or even plain window),
2927 // then implement DLGRESIZE map by specifying controls and groups of control
2928 // and using DLSZ_* values to specify how are they supposed to be resized.
2929 //
2930 // Notes:
2931 // - Resizeable border (WS_THICKFRAME style) should be set in the dialog template
2932 //   for top level dialogs (popup or overlapped), so that users can resize the dialog.
2933 // - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X,
2934 //   DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined.
2935 // - Order of controls is important - group controls are resized and moved based
2936 //   on the position of the previous control in a group.
2937
2938 // dialog resize map macros
2939 #define BEGIN_DLGRESIZE_MAP(thisClass) \
2940         static const _AtlDlgResizeMap* GetDlgResizeMap() \
2941         { \
2942                 static const _AtlDlgResizeMap theMap[] = \
2943                 {
2944
2945 #define END_DLGRESIZE_MAP() \
2946                         { -1, 0 }, \
2947                 }; \
2948                 return theMap; \
2949         }
2950
2951 #define DLGRESIZE_CONTROL(id, flags) \
2952                 { id, flags },
2953
2954 #define BEGIN_DLGRESIZE_GROUP() \
2955                 { -1, _DLSZ_BEGIN_GROUP },
2956
2957 #define END_DLGRESIZE_GROUP() \
2958                 { -1, _DLSZ_END_GROUP },
2959
2960
2961 template <class T>
2962 class CDialogResize
2963 {
2964 public:
2965 // Data declarations and members
2966         enum
2967         {
2968                 DLSZ_SIZE_X             = 0x00000001,
2969                 DLSZ_SIZE_Y             = 0x00000002,
2970                 DLSZ_MOVE_X             = 0x00000004,
2971                 DLSZ_MOVE_Y             = 0x00000008,
2972                 DLSZ_REPAINT            = 0x00000010,
2973                 DLSZ_CENTER_X           = 0x00000020,
2974                 DLSZ_CENTER_Y           = 0x00000040,
2975
2976                 // internal use only
2977                 _DLSZ_BEGIN_GROUP       = 0x00001000,
2978                 _DLSZ_END_GROUP         = 0x00002000,
2979                 _DLSZ_GRIPPER           = 0x00004000
2980         };
2981
2982         struct _AtlDlgResizeMap
2983         {
2984                 int m_nCtlID;
2985                 DWORD m_dwResizeFlags;
2986         };
2987
2988         struct _AtlDlgResizeData
2989         {
2990                 int m_nCtlID;
2991                 DWORD m_dwResizeFlags;
2992                 RECT m_rect;
2993
2994                 int GetGroupCount() const
2995                 {
2996                         return (int)LOBYTE(HIWORD(m_dwResizeFlags));
2997                 }
2998
2999                 void SetGroupCount(int nCount)
3000                 {
3001                         ATLASSERT(nCount > 0 && nCount < 256);
3002                         DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));
3003                         m_dwResizeFlags &= 0xFF00FFFF;
3004                         m_dwResizeFlags |= dwCount;
3005                 }
3006
3007                 bool operator ==(const _AtlDlgResizeData& r) const
3008                 { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); }
3009         };
3010
3011         ATL::CSimpleArray<_AtlDlgResizeData> m_arrData;
3012         SIZE m_sizeDialog;
3013         POINT m_ptMinTrackSize;
3014         bool m_bGripper;
3015
3016
3017 // Constructor
3018         CDialogResize() : m_bGripper(false)
3019         {
3020                 m_sizeDialog.cx = 0;
3021                 m_sizeDialog.cy = 0;
3022                 m_ptMinTrackSize.x = -1;
3023                 m_ptMinTrackSize.y = -1;
3024         }
3025
3026 // Operations
3027         void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN)
3028         {
3029                 T* pT = static_cast<T*>(this);
3030                 ATLASSERT(::IsWindow(pT->m_hWnd));
3031
3032                 DWORD dwStyle = pT->GetStyle();
3033
3034 #ifdef _DEBUG
3035                 // Debug only: Check if top level dialogs have a resizeable border.
3036                 if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0))
3037                         ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n"));
3038 #endif // _DEBUG
3039
3040                 // Force specified styles (default WS_CLIPCHILDREN reduces flicker)
3041                 if((dwStyle & dwForceStyle) != dwForceStyle)
3042                         pT->ModifyStyle(0, dwForceStyle);
3043
3044                 // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have.
3045                 // Setting icon to NULL is required when XP themes are active.
3046                 // Note: This will not prevent adding an icon for the dialog using SetIcon()
3047                 if((dwStyle & WS_CHILD) == 0)
3048                 {
3049                         pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME);
3050                         if(pT->GetIcon(FALSE) == NULL)
3051                                 pT->SetIcon(NULL, FALSE);
3052                 }
3053
3054                 // Cleanup in case of multiple initialization
3055                 // block: first check for the gripper control, destroy it if needed
3056                 {
3057                         ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
3058                         if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)
3059                                 wndGripper.DestroyWindow();
3060                 }
3061                 // clear out everything else
3062                 m_arrData.RemoveAll();
3063                 m_sizeDialog.cx = 0;
3064                 m_sizeDialog.cy = 0;
3065                 m_ptMinTrackSize.x = -1;
3066                 m_ptMinTrackSize.y = -1;
3067
3068                 // Get initial dialog client size
3069                 RECT rectDlg = { 0 };
3070                 pT->GetClientRect(&rectDlg);
3071                 m_sizeDialog.cx = rectDlg.right;
3072                 m_sizeDialog.cy = rectDlg.bottom;
3073
3074 #ifndef _WIN32_WCE
3075                 // Create gripper if requested
3076                 m_bGripper = false;
3077                 if(bAddGripper)
3078                 {
3079                         // shouldn't exist already
3080                         ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)));
3081                         if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)))
3082                         {
3083                                 ATL::CWindow wndGripper;
3084                                 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);
3085                                 ATLASSERT(wndGripper.IsWindow());
3086                                 if(wndGripper.IsWindow())
3087                                 {
3088                                         m_bGripper = true;
3089                                         RECT rectCtl = { 0 };
3090                                         wndGripper.GetWindowRect(&rectCtl);
3091                                         ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
3092                                         _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
3093                                         m_arrData.Add(data);
3094                                 }
3095                         }
3096                 }
3097 #else // CE specific
3098                 bAddGripper;   // avoid level 4 warning
3099 #endif // _WIN32_WCE
3100
3101                 // Get min track position if requested
3102                 if(bUseMinTrackSize)
3103                 {
3104                         if((dwStyle & WS_CHILD) != 0)
3105                         {
3106                                 RECT rect = { 0 };
3107                                 pT->GetClientRect(&rect);
3108                                 m_ptMinTrackSize.x = rect.right - rect.left;
3109                                 m_ptMinTrackSize.y = rect.bottom - rect.top;
3110                         }
3111                         else
3112                         {
3113                                 RECT rect = { 0 };
3114                                 pT->GetWindowRect(&rect);
3115                                 m_ptMinTrackSize.x = rect.right - rect.left;
3116                                 m_ptMinTrackSize.y = rect.bottom - rect.top;
3117                         }
3118                 }
3119
3120                 // Walk the map and initialize data
3121                 const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();
3122                 ATLASSERT(pMap != NULL);
3123                 int nGroupStart = -1;
3124                 for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)
3125                 {
3126                         if(pMap->m_nCtlID == -1)
3127                         {
3128                                 switch(pMap->m_dwResizeFlags)
3129                                 {
3130                                 case _DLSZ_BEGIN_GROUP:
3131                                         ATLASSERT(nGroupStart == -1);
3132                                         nGroupStart = m_arrData.GetSize();
3133                                         break;
3134                                 case _DLSZ_END_GROUP:
3135                                         {
3136                                                 ATLASSERT(nGroupStart != -1);
3137                                                 int nGroupCount = m_arrData.GetSize() - nGroupStart;
3138                                                 m_arrData[nGroupStart].SetGroupCount(nGroupCount);
3139                                                 nGroupStart = -1;
3140                                         }
3141                                         break;
3142                                 default:
3143                                         ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
3144                                         break;
3145                                 }
3146                         }
3147                         else
3148                         {
3149                                 // this ID conflicts with the default gripper one
3150                                 ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);
3151
3152                                 ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);
3153                                 ATLASSERT(ctl.IsWindow());
3154                                 RECT rectCtl = { 0 };
3155                                 ctl.GetWindowRect(&rectCtl);
3156                                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
3157
3158                                 DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;
3159                                 _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
3160                                 m_arrData.Add(data);
3161                         }
3162                 }
3163                 ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
3164         }
3165
3166         void DlgResize_UpdateLayout(int cxWidth, int cyHeight)
3167         {
3168                 T* pT = static_cast<T*>(this);
3169                 ATLASSERT(::IsWindow(pT->m_hWnd));
3170
3171                 // Restrict minimum size if requested
3172                 if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
3173                 {
3174                         if(cxWidth < m_ptMinTrackSize.x)
3175                                 cxWidth = m_ptMinTrackSize.x;
3176                         if(cyHeight < m_ptMinTrackSize.y)
3177                                 cyHeight = m_ptMinTrackSize.y;
3178                 }
3179
3180                 BOOL bVisible = pT->IsWindowVisible();
3181                 if(bVisible)
3182                         pT->SetRedraw(FALSE);
3183
3184                 for(int i = 0; i < m_arrData.GetSize(); i++)
3185                 {
3186                         if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0)   // start of a group
3187                         {
3188                                 int nGroupCount = m_arrData[i].GetGroupCount();
3189                                 ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());
3190                                 RECT rectGroup = m_arrData[i].m_rect;
3191
3192                                 int j = 1;
3193                                 for(j = 1; j < nGroupCount; j++)
3194                                 {
3195                                         rectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left);
3196                                         rectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top);
3197                                         rectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right);
3198                                         rectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
3199                                 }
3200
3201                                 for(j = 0; j < nGroupCount; j++)
3202                                 {
3203                                         _AtlDlgResizeData* pDataPrev = NULL;
3204                                         if(j > 0)
3205                                                 pDataPrev = &(m_arrData[i + j - 1]);
3206                                         pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev);
3207                                 }
3208
3209                                 i += nGroupCount - 1;   // increment to skip all group controls
3210                         }
3211                         else // one control entry
3212                         {
3213                                 RECT rectGroup = { 0, 0, 0, 0 };
3214                                 pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
3215                         }
3216                 }
3217
3218                 if(bVisible)
3219                         pT->SetRedraw(TRUE);
3220
3221                 pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
3222         }
3223
3224 // Message map and handlers
3225         BEGIN_MSG_MAP(CDialogResize)
3226                 MESSAGE_HANDLER(WM_SIZE, OnSize)
3227 #ifndef _WIN32_WCE
3228                 MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
3229 #endif // _WIN32_WCE
3230         END_MSG_MAP()
3231
3232         LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3233         {
3234                 T* pT = static_cast<T*>(this);
3235 #ifndef _WIN32_WCE
3236                 if(m_bGripper)
3237                 {
3238                         ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
3239                         if(wParam == SIZE_MAXIMIZED)
3240                                 wndGripper.ShowWindow(SW_HIDE);
3241                         else if(wParam == SIZE_RESTORED)
3242                                 wndGripper.ShowWindow(SW_SHOW);
3243                 }
3244 #endif // _WIN32_WCE
3245                 if(wParam != SIZE_MINIMIZED)
3246                 {
3247                         ATLASSERT(::IsWindow(pT->m_hWnd));
3248                         pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3249                 }
3250                 return 0;
3251         }
3252
3253 #ifndef _WIN32_WCE
3254         LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
3255         {
3256                 if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
3257                 {
3258                         LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
3259                         lpMMI->ptMinTrackSize =  m_ptMinTrackSize;
3260                 }
3261                 return 0;
3262         }
3263 #endif // _WIN32_WCE
3264
3265 // Implementation
3266         bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, 
3267                                        _AtlDlgResizeData* pDataPrev = NULL)
3268         {
3269                 T* pT = static_cast<T*>(this);
3270                 ATLASSERT(::IsWindow(pT->m_hWnd));
3271                 ATL::CWindow ctl;
3272                 RECT rectCtl = { 0 };
3273
3274                 ctl = pT->GetDlgItem(data.m_nCtlID);
3275                 if(!ctl.GetWindowRect(&rectCtl))
3276                         return false;
3277                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
3278
3279                 if(bGroup)
3280                 {
3281                         if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
3282                         {
3283                                 int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx;
3284                                 int cxCtl = data.m_rect.right - data.m_rect.left;
3285                                 rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2;
3286                                 rectCtl.right = rectCtl.left + cxCtl;
3287                         }
3288                         else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
3289                         {
3290                                 rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
3291
3292                                 if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
3293                                 {
3294                                         rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
3295
3296                                         if(pDataPrev != NULL)
3297                                         {
3298                                                 ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
3299                                                 RECT rcPrev = { 0 };
3300                                                 ctlPrev.GetWindowRect(&rcPrev);
3301                                                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
3302                                                 int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right);
3303                                                 rcPrev.right += dxAdjust;
3304                                                 ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
3305                                         }
3306                                 }
3307                                 else
3308                                 {
3309                                         rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
3310                                 }
3311                         }
3312
3313                         if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
3314                         {
3315                                 int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy;
3316                                 int cyCtl = data.m_rect.bottom - data.m_rect.top;
3317                                 rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2;
3318                                 rectCtl.bottom = rectCtl.top + cyCtl;
3319                         }
3320                         else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
3321                         {
3322                                 rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
3323
3324                                 if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
3325                                 {
3326                                         rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
3327
3328                                         if(pDataPrev != NULL)
3329                                         {
3330                                                 ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
3331                                                 RECT rcPrev = { 0 };
3332                                                 ctlPrev.GetWindowRect(&rcPrev);
3333                                                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
3334                                                 int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom);
3335                                                 rcPrev.bottom += dxAdjust;
3336                                                 ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
3337                                         }
3338                                 }
3339                                 else
3340                                 {
3341                                         rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
3342                                 }
3343                         }
3344                 }
3345                 else // no group
3346                 {
3347                         if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
3348                         {
3349                                 int cxCtl = data.m_rect.right - data.m_rect.left;
3350                                 rectCtl.left = (cxWidth - cxCtl) / 2;
3351                                 rectCtl.right = rectCtl.left + cxCtl;
3352                         }
3353                         else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
3354                         {
3355                                 rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
3356
3357                                 if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
3358                                         rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
3359                         }
3360
3361                         if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
3362                         {
3363                                 int cyCtl = data.m_rect.bottom - data.m_rect.top;
3364                                 rectCtl.top = (cyHeight - cyCtl) / 2;
3365                                 rectCtl.bottom = rectCtl.top + cyCtl;
3366                         }
3367                         else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
3368                         {
3369                                 rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
3370
3371                                 if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
3372                                         rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
3373                         }
3374                 }
3375
3376                 if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
3377                         ctl.Invalidate();
3378
3379                 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)
3380                         ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);
3381
3382                 return true;
3383         }
3384 };
3385
3386
3387 ///////////////////////////////////////////////////////////////////////////////
3388 // CDoubleBufferImpl - Provides double-buffer painting support to any window
3389
3390 template <class T>
3391 class CDoubleBufferImpl
3392 {
3393 public:
3394 // Overrideables
3395         void DoPaint(CDCHandle /*dc*/)
3396         {
3397                 // must be implemented in a derived class
3398                 ATLASSERT(FALSE);
3399         }
3400
3401 // Message map and handlers
3402         BEGIN_MSG_MAP(CDoubleBufferImpl)
3403                 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
3404                 MESSAGE_HANDLER(WM_PAINT, OnPaint)
3405 #ifndef _WIN32_WCE
3406                 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
3407 #endif // !_WIN32_WCE
3408         END_MSG_MAP()
3409
3410         LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
3411         {
3412                 return 1;   // no background painting needed
3413         }
3414
3415         LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
3416         {
3417                 T* pT = static_cast<T*>(this);
3418                 ATLASSERT(::IsWindow(pT->m_hWnd));
3419
3420                 if(wParam != NULL)
3421                 {
3422                         RECT rect = { 0 };
3423                         pT->GetClientRect(&rect);
3424                         CMemoryDC dcMem((HDC)wParam, rect);
3425                         pT->DoPaint(dcMem.m_hDC);
3426                 }
3427                 else
3428                 {
3429                         CPaintDC dc(pT->m_hWnd);
3430                         CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);
3431                         pT->DoPaint(dcMem.m_hDC);
3432                 }
3433
3434                 return 0;
3435         }
3436 };
3437
3438
3439 ///////////////////////////////////////////////////////////////////////////////
3440 // CDoubleBufferWindowImpl - Implements a double-buffer painting window
3441
3442 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
3443 class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T >
3444 {
3445 public:
3446         BEGIN_MSG_MAP(CDoubleBufferWindowImpl)
3447                 CHAIN_MSG_MAP(CDoubleBufferImpl< T >)
3448         END_MSG_MAP()
3449 };
3450
3451
3452 // command bar support
3453 #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
3454   #undef CBRM_GETMENU
3455   #undef CBRM_TRACKPOPUPMENU
3456   #undef CBRM_GETCMDBAR
3457   #undef CBRPOPUPMENU
3458 #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
3459
3460 }; // namespace WTL
3461
3462 #endif // __ATLFRAME_H__