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