- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / wtl / include / atldlgs.h
1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
8
9 #ifndef __ATLDLGS_H__
10 #define __ATLDLGS_H__
11
12 #pragma once
13
14 #ifndef __cplusplus
15         #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
17
18 #ifndef __ATLAPP_H__
19         #error atldlgs.h requires atlapp.h to be included first
20 #endif
21
22 #ifndef __ATLWIN_H__
23         #error atldlgs.h requires atlwin.h to be included first
24 #endif
25
26 #include <commdlg.h>
27 #include <shlobj.h>
28
29 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
30   #include <shobjidl.h>
31 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
32
33
34 ///////////////////////////////////////////////////////////////////////////////
35 // Classes in this file:
36 //
37 // CFileDialogImpl<T>
38 // CFileDialog
39 // CFileDialogEx
40 // CMultiFileDialogImpl<T>
41 // CMultiFileDialog
42 // CShellFileDialogImpl<T>
43 // CShellFileOpenDialogImpl<T>
44 // CShellFileOpenDialog
45 // CShellFileSaveDialogImpl<T>
46 // CShellFileSaveDialog
47 // CFolderDialogImpl<T>
48 // CFolderDialog
49 // CFontDialogImpl<T>
50 // CFontDialog
51 // CRichEditFontDialogImpl<T>
52 // CRichEditFontDialog
53 // CColorDialogImpl<T>
54 // CColorDialog
55 // CPrintDialogImpl<T>
56 // CPrintDialog
57 // CPrintDialogExImpl<T>
58 // CPrintDialogEx
59 // CPageSetupDialogImpl<T>
60 // CPageSetupDialog
61 // CFindReplaceDialogImpl<T>
62 // CFindReplaceDialog
63 //
64 // CMemDlgTemplate
65 // CIndirectDialogImpl<T, TDlgTemplate, TBase>
66 //
67 // CPropertySheetWindow
68 // CPropertySheetImpl<T, TBase>
69 // CPropertySheet
70 // CPropertyPageWindow
71 // CPropertyPageImpl<T, TBase>
72 // CPropertyPage<t_wDlgTemplateID>
73 // CAxPropertyPageImpl<T, TBase>
74 // CAxPropertyPage<t_wDlgTemplateID>
75 //
76 // CWizard97SheetWindow
77 // CWizard97SheetImpl<T, TBase>
78 // CWizard97Sheet
79 // CWizard97PageWindow
80 // CWizard97PageImpl<T, TBase>
81 // CWizard97ExteriorPageImpl<T, TBase>
82 // CWizard97InteriorPageImpl<T, TBase>
83 //
84 // CAeroWizardFrameWindow
85 // CAeroWizardFrameImpl<T, TBase>
86 // CAeroWizardFrame
87 // CAeroWizardPageWindow
88 // CAeroWizardPageImpl<T, TBase>
89 // CAeroWizardPage<t_wDlgTemplateID>
90 // CAeroWizardAxPageImpl<T, TBase>
91 // CAeroWizardAxPage<t_wDlgTemplateID>
92 //
93 // CTaskDialogConfig
94 // CTaskDialogImpl<T>
95 // CTaskDialog
96 //
97 // Global functions:
98 //   AtlTaskDialog()
99
100
101 namespace WTL
102 {
103
104 ///////////////////////////////////////////////////////////////////////////////
105 // CFileDialogImpl - used for File Open or File Save As
106
107 // compatibility with the old (vc6.0) headers
108 #if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
109   #ifndef CDSIZEOF_STRUCT
110     #define CDSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
111   #endif
112   #define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
113   #define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
114   #ifdef UNICODE
115     #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400W
116   #else
117     #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400A
118   #endif // !UNICODE
119 #endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
120
121 #if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM)
122   #define CDN_INCLUDEITEM         (CDN_FIRST - 0x0007)
123 #endif
124
125 template <class T>
126 class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase
127 {
128 public:
129 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
130         OPENFILENAMEEX m_ofn;
131 #else
132         OPENFILENAME m_ofn;
133 #endif
134         BOOL m_bOpenFileDialog;            // TRUE for file open, FALSE for file save
135         TCHAR m_szFileTitle[_MAX_FNAME];   // contains file title after return
136         TCHAR m_szFileName[_MAX_PATH];     // contains full path name after return
137
138         CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
139                         LPCTSTR lpszDefExt = NULL,
140                         LPCTSTR lpszFileName = NULL,
141                         DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
142                         LPCTSTR lpszFilter = NULL,
143                         HWND hWndParent = NULL)
144         {
145                 memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
146                 m_szFileName[0] = _T('\0');
147                 m_szFileTitle[0] = _T('\0');
148
149                 m_bOpenFileDialog = bOpenFileDialog;
150
151                 m_ofn.lStructSize = sizeof(m_ofn);
152 #if (_WIN32_WINNT >= 0x0500)
153                 // adjust struct size if running on older version of Windows
154                 if(AtlIsOldWindows())
155                 {
156                         ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400);   // must be
157                         m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
158                 }
159 #endif // (_WIN32_WINNT >= 0x0500)
160                 m_ofn.lpstrFile = m_szFileName;
161                 m_ofn.nMaxFile = _MAX_PATH;
162                 m_ofn.lpstrDefExt = lpszDefExt;
163                 m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
164                 m_ofn.nMaxFileTitle = _MAX_FNAME;
165 #ifndef _WIN32_WCE
166                 m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;
167 #else // CE specific
168                 m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;
169 #endif // !_WIN32_WCE
170                 m_ofn.lpstrFilter = lpszFilter;
171                 m_ofn.hInstance = ModuleHelper::GetResourceInstance();
172                 m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;
173                 m_ofn.hwndOwner = hWndParent;
174
175                 // setup initial file name
176                 if(lpszFileName != NULL)
177                 SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);
178         }
179
180         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
181         {
182                 ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);
183                 ATLASSERT(m_ofn.lpfnHook != NULL);   // can still be a user hook
184
185                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
186
187                 if(m_ofn.hwndOwner == NULL)   // set only if not specified before
188                         m_ofn.hwndOwner = hWndParent;
189
190                 ATLASSERT(m_hWnd == NULL);
191                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);
192
193                 BOOL bRet;
194                 if(m_bOpenFileDialog)
195 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
196                         bRet = ::GetOpenFileNameEx(&m_ofn);
197                 else
198                         bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn);
199 #else
200                         bRet = ::GetOpenFileName(&m_ofn);
201                 else
202                         bRet = ::GetSaveFileName(&m_ofn);
203 #endif
204
205                 m_hWnd = NULL;
206
207                 return bRet ? IDOK : IDCANCEL;
208         }
209
210 // Attributes
211         ATL::CWindow GetFileDialogWindow() const
212         {
213                 ATLASSERT(::IsWindow(m_hWnd));
214                 return ATL::CWindow(GetParent());
215         }
216
217         int GetFilePath(LPTSTR lpstrFilePath, int nLength) const
218         {
219                 ATLASSERT(::IsWindow(m_hWnd));
220                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
221
222                 return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath);
223         }
224
225         int GetFolderIDList(LPVOID lpBuff, int nLength) const
226         {
227                 ATLASSERT(::IsWindow(m_hWnd));
228                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
229
230                 return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff);
231         }
232
233         int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const
234         {
235                 ATLASSERT(::IsWindow(m_hWnd));
236                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
237
238                 return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath);
239         }
240
241         int GetSpec(LPTSTR lpstrSpec, int nLength) const
242         {
243                 ATLASSERT(::IsWindow(m_hWnd));
244                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
245
246                 return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec);
247         }
248
249         void SetControlText(int nCtrlID, LPCTSTR lpstrText)
250         {
251                 ATLASSERT(::IsWindow(m_hWnd));
252                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
253
254                 GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText);
255         }
256
257         void SetDefExt(LPCTSTR lpstrExt)
258         {
259                 ATLASSERT(::IsWindow(m_hWnd));
260                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
261
262                 GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt);
263         }
264
265         BOOL GetReadOnlyPref() const    // return TRUE if readonly checked
266         {
267                 return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE;
268         }
269
270 // Operations
271         void HideControl(int nCtrlID)
272         {
273                 ATLASSERT(::IsWindow(m_hWnd));
274                 ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
275
276                 GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID);
277         }
278
279 // Special override for common dialogs
280         BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
281         {
282                 ATLASSERT(::IsWindow(m_hWnd));
283                 GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0));
284                 return TRUE;
285         }
286
287 // Message map and handlers
288         BEGIN_MSG_MAP(CFileDialogImpl)
289                 NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK)
290                 NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange)
291                 NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp)
292                 NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone)
293                 NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange)
294                 NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation)
295                 NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange)
296 #ifndef _WIN32_WCE
297                 NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem)
298 #endif // !_WIN32_WCE
299         END_MSG_MAP()
300
301         LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
302         {
303                 ATLASSERT(::IsWindow(m_hWnd));
304                 T* pT = static_cast<T*>(this);
305                 return !pT->OnFileOK((LPOFNOTIFY)pnmh);
306         }
307
308         LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
309         {
310                 ATLASSERT(::IsWindow(m_hWnd));
311                 T* pT = static_cast<T*>(this);
312                 pT->OnFolderChange((LPOFNOTIFY)pnmh);
313                 return 0;
314         }
315
316         LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
317         {
318                 ATLASSERT(::IsWindow(m_hWnd));
319                 T* pT = static_cast<T*>(this);
320                 pT->OnHelp((LPOFNOTIFY)pnmh);
321                 return 0;
322         }
323
324         LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
325         {
326                 ATLASSERT(::IsWindow(m_hWnd));
327                 T* pT = static_cast<T*>(this);
328                 pT->OnInitDone((LPOFNOTIFY)pnmh);
329                 return 0;
330         }
331
332         LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
333         {
334                 ATLASSERT(::IsWindow(m_hWnd));
335                 T* pT = static_cast<T*>(this);
336                 pT->OnSelChange((LPOFNOTIFY)pnmh);
337                 return 0;
338         }
339
340         LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
341         {
342                 ATLASSERT(::IsWindow(m_hWnd));
343                 T* pT = static_cast<T*>(this);
344                 return pT->OnShareViolation((LPOFNOTIFY)pnmh);
345         }
346
347         LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
348         {
349                 ATLASSERT(::IsWindow(m_hWnd));
350                 T* pT = static_cast<T*>(this);
351                 pT->OnTypeChange((LPOFNOTIFY)pnmh);
352                 return 0;
353         }
354
355 #ifndef _WIN32_WCE
356         LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
357         {
358                 ATLASSERT(::IsWindow(m_hWnd));
359                 T* pT = static_cast<T*>(this);
360                 return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh);
361         }
362 #endif // !_WIN32_WCE
363
364 // Overrideables
365         BOOL OnFileOK(LPOFNOTIFY /*lpon*/)
366         {
367                 return TRUE;
368         }
369
370         void OnFolderChange(LPOFNOTIFY /*lpon*/)
371         {
372         }
373
374         void OnHelp(LPOFNOTIFY /*lpon*/)
375         {
376         }
377
378         void OnInitDone(LPOFNOTIFY /*lpon*/)
379         {
380         }
381
382         void OnSelChange(LPOFNOTIFY /*lpon*/)
383         {
384         }
385
386         int OnShareViolation(LPOFNOTIFY /*lpon*/)
387         {
388                 return 0;
389         }
390
391         void OnTypeChange(LPOFNOTIFY /*lpon*/)
392         {
393         }
394
395 #ifndef _WIN32_WCE
396         BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/)
397         {
398                 return TRUE;   // include item
399         }
400 #endif // !_WIN32_WCE
401 };
402
403 class CFileDialog : public CFileDialogImpl<CFileDialog>
404 {
405 public:
406         CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
407                 LPCTSTR lpszDefExt = NULL,
408                 LPCTSTR lpszFileName = NULL,
409                 DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
410                 LPCTSTR lpszFilter = NULL,
411                 HWND hWndParent = NULL)
412                 : CFileDialogImpl<CFileDialog>(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
413         { }
414
415         // override base class map and references to handlers
416         DECLARE_EMPTY_MSG_MAP()
417 };
418
419 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
420 class CFileDialogEx : public CFileDialogImpl<CFileDialogEx>
421 {
422 public:
423         CFileDialogEx( // Supports only FileOpen
424                 LPCTSTR lpszDefExt = NULL,
425                 LPCTSTR lpszFileName = NULL,
426                 DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
427                 OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW,
428                 OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO,         
429                 LPCTSTR lpszFilter = NULL,
430                 HWND hWndParent = NULL)
431                 : CFileDialogImpl<CFileDialogEx>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
432         {
433                 m_ofn.ExFlags = ExFlags;
434                 m_ofn.dwSortOrder = dwSortOrder;
435         }
436
437         // override base class map and references to handlers
438         DECLARE_EMPTY_MSG_MAP()
439 };
440 #endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
441
442
443 ///////////////////////////////////////////////////////////////////////////////
444 // Multi File Dialog - Multi-select File Open dialog
445
446 #ifndef _WIN32_WCE
447
448 // The class dynamically resizes the buffer as the file selection changes
449 // (as described in Knowledge Base article 131462). It also expands selected
450 // shortcut files to take into account the full path of the target file.
451 // Note that this doesn't work on Win9x for the old style dialogs, as well as
452 // on NT for non-Unicode builds. 
453
454 #ifndef _WTL_FIXED_OFN_BUFFER_LENGTH
455   #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000
456 #endif
457
458 template <class T>
459 class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T >
460 {
461 public:
462         mutable LPCTSTR m_pNextFile; 
463 #ifndef _UNICODE
464         bool m_bIsNT;
465 #endif
466
467         CMultiFileDialogImpl(
468                 LPCTSTR lpszDefExt = NULL,
469                 LPCTSTR lpszFileName = NULL,
470                 DWORD dwFlags = OFN_HIDEREADONLY,
471                 LPCTSTR lpszFilter = NULL,
472                 HWND hWndParent = NULL)
473                 : CFileDialogImpl<T>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent), 
474                   m_pNextFile(NULL)
475         {
476                 m_ofn.Flags |= OFN_ALLOWMULTISELECT;   // Force multiple selection mode
477
478 #ifndef _UNICODE
479                 OSVERSIONINFO ovi = { sizeof(ovi) };
480                 ::GetVersionEx(&ovi);
481                 m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT);
482                 if (m_bIsNT)
483                 {
484                         // On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there 
485                         // is absolutely nothing we can do except to start off with a large buffer.
486                         ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH));
487                 }
488 #endif
489         }
490
491         ~CMultiFileDialogImpl()
492         {
493                 if (m_ofn.lpstrFile != m_szFileName)   // Free the buffer if we allocated it
494                         delete[] m_ofn.lpstrFile;
495         }
496
497 // Operations
498         // Get the directory that the files were chosen from.
499         // The function returns the number of characters copied, not including the terminating zero. 
500         // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
501         // If the function fails, the return value is zero.
502         int GetDirectory(LPTSTR pBuffer, int nBufLen) const
503         {
504                 if (m_ofn.lpstrFile == NULL)
505                         return 0;
506
507                 LPCTSTR pStr = m_ofn.lpstrFile;
508                 int nLength = lstrlen(pStr);
509                 if (pStr[nLength + 1] == 0)
510                 {
511                         // The OFN buffer contains a single item so extract its path.
512                         LPCTSTR pSep = _strrchr(pStr, _T('\\'));
513                         if (pSep != NULL)
514                                 nLength = (int)(DWORD_PTR)(pSep - pStr);
515                 }
516
517                 int nRet = 0;
518                 if (pBuffer == NULL)   // If the buffer is NULL, return the required length
519                 {
520                         nRet = nLength + 1;
521                 }
522                 else if (nBufLen > nLength)
523                 {
524                         SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength);
525                         nRet = nLength;
526                 }
527
528                 return nRet;
529         }
530
531 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
532         bool GetDirectory(_CSTRING_NS::CString& strDir) const
533         {
534                 bool bRet = false;
535
536                 int nLength = GetDirectory(NULL, 0);
537                 if (nLength > 0)
538                 {
539                         bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0);
540                         strDir.ReleaseBuffer(nLength - 1);
541                 }
542
543                 return bRet;
544         }
545 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
546
547         // Get the first filename as a pointer into the buffer.
548         LPCTSTR GetFirstFileName() const
549         {
550                 if (m_ofn.lpstrFile == NULL)
551                         return NULL;
552
553                 m_pNextFile = NULL;   // Reset internal buffer pointer
554
555                 LPCTSTR pStr = m_ofn.lpstrFile;
556                 int nLength = lstrlen(pStr);
557                 if (pStr[nLength + 1] != 0)
558                 {
559                         // Multiple items were selected. The first string is the directory,
560                         // so skip forwards to the second string.
561                         pStr += nLength + 1;
562
563                         // Set up m_pNext so it points to the second item (or null).
564                         m_pNextFile = pStr;
565                         GetNextFileName();
566                 }
567                 else
568                 {
569                         // A single item was selected. Skip forward past the path.
570                         LPCTSTR pSep = _strrchr(pStr, _T('\\'));
571                         if (pSep != NULL)
572                                 pStr = pSep + 1;
573                 }
574
575                 return pStr;
576         }
577
578         // Get the next filename as a pointer into the buffer.
579         LPCTSTR GetNextFileName() const
580         {
581                 if (m_pNextFile == NULL)
582                         return NULL;
583
584                 LPCTSTR pStr = m_pNextFile;
585                 // Set "m_pNextFile" to point to the next file name, or null if we 
586                 // have reached the last file in the list.
587                 int nLength = lstrlen(pStr);
588                 m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL;
589
590                 return pStr;
591         }
592
593         // Get the first filename as a full path.
594         // The function returns the number of characters copied, not including the terminating zero. 
595         // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
596         // If the function fails, the return value is zero.
597         int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const
598         {
599                 LPCTSTR pStr = GetFirstFileName();
600                 int nLengthDir = GetDirectory(NULL, 0);
601                 if((pStr == NULL) || (nLengthDir == 0))
602                         return 0;
603
604                 // Figure out the required length.
605                 int nLengthTotal = nLengthDir + lstrlen(pStr);
606
607                 int nRet = 0;
608                 if(pBuffer == NULL) // If the buffer is NULL, return the required length
609                 {
610                         nRet = nLengthTotal + 1;
611                 }
612                 else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
613                 {               
614                         GetDirectory(pBuffer, nBufLen);
615                         SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
616                         SecureHelper::strcat_x(pBuffer, nBufLen, pStr);
617                         nRet = nLengthTotal;
618                 }
619
620                 return nRet;
621         }
622
623 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
624         bool GetFirstPathName(_CSTRING_NS::CString& strPath) const
625         {
626                 bool bRet = false;
627
628                 int nLength = GetFirstPathName(NULL, 0);
629                 if (nLength > 0)
630                 {
631                         bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0);
632                         strPath.ReleaseBuffer(nLength - 1);
633                 }
634
635                 return bRet;
636         }
637 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
638
639         // Get the next filename as a full path.
640         // The function returns the number of characters copied, not including the terminating zero. 
641         // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
642         // If the function fails, the return value is zero.
643         // The internal position marker is moved forward only if the function succeeds and the buffer was large enough.
644         int GetNextPathName(LPTSTR pBuffer, int nBufLen) const
645         {
646                 if (m_pNextFile == NULL)
647                         return 0;
648
649                 int nRet = 0;
650                 LPCTSTR pStr = m_pNextFile;
651                 // Does the filename contain a backslash?
652                 if (_strrchr(pStr, _T('\\')) != NULL)
653                 {
654                         // Yes, so we'll assume it's a full path.
655                         int nLength = lstrlen(pStr);
656
657                         if (pBuffer == NULL) // If the buffer is NULL, return the required length
658                         {
659                                 nRet = nLength + 1;
660                         }
661                         else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename
662                         {
663                                 SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName());
664                                 nRet = nBufLen;
665                         }
666                 }
667                 else
668                 {
669                         // The filename is relative, so construct the full path.
670                         int nLengthDir = GetDirectory(NULL, 0);
671                         if (nLengthDir > 0)
672                         {
673                                 // Calculate the required space.
674                                 int nLengthTotal = nLengthDir + lstrlen(pStr);
675
676                                 if(pBuffer == NULL) // If the buffer is NULL, return the required length
677                                 {
678                                         nRet = nLengthTotal + 1;
679                                 }
680                                 else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
681                                 {
682                                         GetDirectory(pBuffer, nBufLen);
683                                         SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
684                                         SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName());
685                                         nRet = nLengthTotal;
686                                 }
687                         }
688                 }
689
690                 return nRet;
691         }
692
693 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
694         bool GetNextPathName(_CSTRING_NS::CString& strPath) const
695         {
696                 bool bRet = false;
697
698                 int nLength = GetNextPathName(NULL, 0);
699                 if (nLength > 0)
700                 {
701                         bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0);
702                         strPath.ReleaseBuffer(nLength - 1);
703                 }
704
705                 return bRet;
706         }
707 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
708
709 // Implementation
710         bool ResizeFilenameBuffer(DWORD dwLength)
711         {
712                 if (dwLength > m_ofn.nMaxFile)
713                 {
714                         // Free the old buffer.
715                         if (m_ofn.lpstrFile != m_szFileName)
716                         {
717                                 delete[] m_ofn.lpstrFile;
718                                 m_ofn.lpstrFile = NULL;
719                                 m_ofn.nMaxFile = 0;
720                         }
721
722                         // Allocate the new buffer.
723                         LPTSTR lpstrBuff = NULL;
724                         ATLTRY(lpstrBuff = new TCHAR[dwLength]);
725                         if (lpstrBuff != NULL)
726                         {
727                                 m_ofn.lpstrFile = lpstrBuff;
728                                 m_ofn.lpstrFile[0] = 0;
729                                 m_ofn.nMaxFile = dwLength;
730                         }
731                 }
732
733                 return (m_ofn.lpstrFile != NULL);
734         }
735
736         void OnSelChange(LPOFNOTIFY /*lpon*/)
737         {
738 #ifndef _UNICODE
739                 // There is no point resizing the buffer in ANSI builds running on NT.
740                 if (m_bIsNT)
741                         return;
742 #endif
743
744                 // Get the buffer length required to hold the spec.
745                 int nLength = GetSpec(NULL, 0);
746                 if (nLength <= 1)
747                         return; // no files are selected, presumably
748                 
749                 // Add room for the directory, and an extra terminating zero.
750                 nLength += GetFolderPath(NULL, 0) + 1;
751
752                 if (!ResizeFilenameBuffer(nLength))
753                 {
754                         ATLASSERT(FALSE);
755                         return;
756                 }
757
758                 // If we are not following links then our work is done.
759                 if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0)
760                         return;
761
762                 // Get the file spec, which is the text in the edit control.
763                 if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0)
764                         return;
765                 
766                 // Get the ID-list of the current folder.
767                 int nBytes = GetFolderIDList(NULL, 0);
768                 CTempBuffer<ITEMIDLIST> idlist;
769                 idlist.AllocateBytes(nBytes);
770                 if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0))
771                         return;
772
773                 // First bind to the desktop folder, then to the current folder.
774                 ATL::CComPtr<IShellFolder> pDesktop, pFolder;
775                 if (FAILED(::SHGetDesktopFolder(&pDesktop)))
776                         return;
777                 if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder)))
778                         return;
779
780                 // Work through the file spec, looking for quoted filenames. If we find a shortcut file, then 
781                 // we need to add enough extra buffer space to hold its target path.
782                 DWORD nExtraChars = 0;
783                 bool bInsideQuotes = false;
784                 LPCTSTR pAnchor = m_ofn.lpstrFile;
785                 LPCTSTR pChar = m_ofn.lpstrFile;
786                 for ( ; *pChar; ++pChar)
787                 {
788                         // Look for quotation marks.
789                         if (*pChar == _T('\"'))
790                         {
791                                 // We are either entering or leaving a passage of quoted text.
792                                 bInsideQuotes = !bInsideQuotes;
793
794                                 // Is it an opening or closing quote?
795                                 if (bInsideQuotes)
796                                 {
797                                         // We found an opening quote, so set "pAnchor" to the following character.
798                                         pAnchor = pChar + 1;
799                                 }
800                                 else // closing quote
801                                 {
802                                         // Each quoted entity should be shorter than MAX_PATH.
803                                         if (pChar - pAnchor >= MAX_PATH)
804                                                 return;
805
806                                         // Get the ID-list and attributes of the file.
807                                         USES_CONVERSION;
808                                         int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor);
809                                         TCHAR szFileName[MAX_PATH];
810                                         SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength);
811                                         LPITEMIDLIST pidl = NULL;
812                                         DWORD dwAttrib = SFGAO_LINK;
813                                         if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib)))
814                                         {
815                                                 // Is it a shortcut file?
816                                                 if (dwAttrib & SFGAO_LINK)
817                                                 {
818                                                         // Bind to its IShellLink interface.
819                                                         ATL::CComPtr<IShellLink> pLink;
820                                                         if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink)))
821                                                         {
822                                                                 // Get the shortcut's target path.
823                                                                 TCHAR szPath[MAX_PATH];
824                                                                 if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0)))
825                                                                 {
826                                                                         // If the target path is longer than the shortcut name, then add on the number 
827                                                                         // of extra characters that are required.
828                                                                         int nNewLength = lstrlen(szPath);
829                                                                         if (nNewLength > nFileNameLength)
830                                                                                 nExtraChars += nNewLength - nFileNameLength;
831                                                                 }
832                                                         }
833                                                 }
834
835                                                 // Free the ID-list returned by ParseDisplayName.
836                                                 ::CoTaskMemFree(pidl);
837                                         }
838                                 }
839                         }
840                 }
841
842                 // If we need more space for shortcut targets, then reallocate.
843                 if (nExtraChars > 0)
844                         ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars));
845         }
846
847         // Helper for _ATM_MIN_CRT
848         static const TCHAR* _strrchr(const TCHAR* p, TCHAR ch)
849         {
850 #ifndef _ATL_MIN_CRT
851                 return _tcsrchr(p, ch);
852 #else // _ATL_MIN_CRT
853                 const TCHAR* lpsz = NULL;
854                 while (*p != 0)
855                 {
856                         if (*p == ch)
857                                 lpsz = p;
858                         p = ::CharNext(p);
859                 }
860                 return lpsz;
861 #endif // _ATL_MIN_CRT
862         }
863 };
864
865 class CMultiFileDialog : public CMultiFileDialogImpl<CMultiFileDialog>
866 {
867 public:
868         CMultiFileDialog(
869                 LPCTSTR lpszDefExt = NULL,
870                 LPCTSTR lpszFileName = NULL,
871                 DWORD dwFlags = OFN_HIDEREADONLY,
872                 LPCTSTR lpszFilter = NULL,
873                 HWND hWndParent = NULL)
874                 : CMultiFileDialogImpl<CMultiFileDialog>(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
875         { }
876
877         BEGIN_MSG_MAP(CMultiFileDialog)
878                 CHAIN_MSG_MAP(CMultiFileDialogImpl<CMultiFileDialog>)
879         END_MSG_MAP()
880 };
881
882 #endif // !_WIN32_WCE
883
884
885 ///////////////////////////////////////////////////////////////////////////////
886 // Shell File Dialog - new Shell File Open and Save dialogs in Vista
887
888 // Note: Use GetPtr() to access dialog interface methods.
889 // Example:
890 //      CShellFileOpenDialog dlg;
891 //      dlg.GetPtr()->SetTitle(L"MyFileOpenDialog");
892
893 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
894
895 ///////////////////////////////////////////////////////////////////////////////
896 // CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl
897
898 template <class T>
899 class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents
900 {
901 public:
902 // Operations
903         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
904         {
905                 INT_PTR nRet = -1;
906
907                 T* pT = static_cast<T*>(this);
908                 if(pT->m_spFileDlg == NULL)
909                 {
910                         ATLASSERT(FALSE);
911                         return nRet;
912                 }
913
914                 DWORD dwCookie = 0;
915                 pT->_Advise(dwCookie);
916
917                 HRESULT hRet = pT->m_spFileDlg->Show(hWndParent);
918                 if(SUCCEEDED(hRet))
919                         nRet = IDOK;
920                 else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED))
921                         nRet = IDCANCEL;
922                 else
923                         ATLASSERT(FALSE);   // error
924
925                 pT->_Unadvise(dwCookie);
926
927                 return nRet;
928         }
929
930         bool IsNull() const
931         {
932                 const T* pT = static_cast<const T*>(this);
933                 return (pT->m_spFileDlg == NULL);
934         }
935
936 // Operations - get file path after dialog returns
937         HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength)
938         {
939                 T* pT = static_cast<T*>(this);
940                 ATLASSERT(pT->m_spFileDlg != NULL);
941
942                 ATL::CComPtr<IShellItem> spItem;
943                 HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
944
945                 if(SUCCEEDED(hRet))
946                         hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength);
947
948                 return hRet;
949         }
950
951         HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength)
952         {
953                 T* pT = static_cast<T*>(this);
954                 ATLASSERT(pT->m_spFileDlg != NULL);
955
956                 ATL::CComPtr<IShellItem> spItem;
957                 HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
958
959                 if(SUCCEEDED(hRet))
960                         hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength);
961
962                 return hRet;
963         }
964
965 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
966         HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath)
967         {
968                 T* pT = static_cast<T*>(this);
969                 ATLASSERT(pT->m_spFileDlg != NULL);
970
971                 ATL::CComPtr<IShellItem> spItem;
972                 HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
973
974                 if(SUCCEEDED(hRet))
975                         hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath);
976
977                 return hRet;
978         }
979
980         HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle)
981         {
982                 T* pT = static_cast<T*>(this);
983                 ATLASSERT(pT->m_spFileDlg != NULL);
984
985                 ATL::CComPtr<IShellItem> spItem;
986                 HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
987
988                 if(SUCCEEDED(hRet))
989                         hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle);
990
991                 return hRet;
992         }
993 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
994
995 // Helpers for IShellItem
996         static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength)
997         {
998                 ATLASSERT(pShellItem != NULL);
999
1000                 LPWSTR lpstrName = NULL;
1001                 HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
1002
1003                 if(SUCCEEDED(hRet))
1004                 {
1005                         if(lstrlenW(lpstrName) < cchLength)
1006                         {
1007                                 SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName);
1008                         }
1009                         else
1010                         {
1011                                 ATLASSERT(FALSE);
1012                                 hRet = DISP_E_BUFFERTOOSMALL;
1013                         }
1014
1015                         ::CoTaskMemFree(lpstrName);
1016                 }
1017
1018                 return hRet;
1019         }
1020
1021 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
1022         static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str)
1023         {
1024                 ATLASSERT(pShellItem != NULL);
1025
1026                 LPWSTR lpstrName = NULL;
1027                 HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
1028
1029                 if(SUCCEEDED(hRet))
1030                 {
1031                         str = lpstrName;
1032                         ::CoTaskMemFree(lpstrName);
1033                 }
1034
1035                 return hRet;
1036         }
1037 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
1038
1039 // Implementation
1040         void _Advise(DWORD& dwCookie)
1041         {
1042                 T* pT = static_cast<T*>(this);
1043                 ATLASSERT(pT->m_spFileDlg != NULL);
1044                 HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie);
1045                 ATLVERIFY(SUCCEEDED(hRet));
1046         }
1047
1048         void _Unadvise(DWORD dwCookie)
1049         {
1050                 T* pT = static_cast<T*>(this);
1051                 ATLASSERT(pT->m_spFileDlg != NULL);
1052                 HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie);
1053                 ATLVERIFY(SUCCEEDED(hRet));
1054         }
1055
1056         void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount)
1057         {
1058                 T* pT = static_cast<T*>(this);
1059                 ATLASSERT(pT->m_spFileDlg != NULL);
1060
1061                 HRESULT hRet = E_FAIL;
1062
1063                 if(lpszFileName != NULL)
1064                 {
1065                         hRet = pT->m_spFileDlg->SetFileName(lpszFileName);
1066                         ATLASSERT(SUCCEEDED(hRet));
1067                 }
1068
1069                 hRet = pT->m_spFileDlg->SetOptions(dwOptions);
1070                 ATLASSERT(SUCCEEDED(hRet));
1071
1072                 if(lpszDefExt != NULL)
1073                 {
1074                         hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt);
1075                         ATLASSERT(SUCCEEDED(hRet));
1076                 }
1077
1078                 if(arrFilterSpec != NULL && uFilterSpecCount != 0U)
1079                 {
1080                         hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec);
1081                         ATLASSERT(SUCCEEDED(hRet));
1082                 }
1083         }
1084
1085 // Implementation - IUnknown interface
1086         STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
1087         {
1088                 if(ppvObject == NULL)
1089                         return E_POINTER;
1090
1091                 T* pT = static_cast<T*>(this);
1092                 if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents))
1093                 {
1094                         *ppvObject = (IFileDialogEvents*)pT;
1095                         // AddRef() not needed
1096                         return S_OK;
1097                 }
1098
1099                 return E_NOINTERFACE;
1100         }
1101
1102         virtual ULONG STDMETHODCALLTYPE AddRef()
1103         {
1104                 return 1;
1105         }
1106
1107         virtual ULONG STDMETHODCALLTYPE Release()
1108         {
1109                 return 1;
1110         }
1111
1112 // Implementation - IFileDialogEvents interface
1113         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd)
1114         {
1115                 T* pT = static_cast<T*>(this);
1116                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1117                 pfd;   // avoid level 4 warning
1118                 return pT->OnFileOk();
1119         }
1120
1121         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder)
1122         {
1123                 T* pT = static_cast<T*>(this);
1124                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1125                 pfd;   // avoid level 4 warning
1126                 return pT->OnFolderChanging(psiFolder);
1127         }
1128
1129         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd)
1130         {
1131                 T* pT = static_cast<T*>(this);
1132                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1133                 pfd;   // avoid level 4 warning
1134                 return pT->OnFolderChange();
1135         }
1136
1137         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd)
1138         {
1139                 T* pT = static_cast<T*>(this);
1140                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1141                 pfd;   // avoid level 4 warning
1142                 return pT->OnSelectionChange();
1143         }
1144
1145         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse)
1146         {
1147                 T* pT = static_cast<T*>(this);
1148                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1149                 pfd;   // avoid level 4 warning
1150                 return pT->OnShareViolation(psi, pResponse);
1151         }
1152
1153         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd)
1154         {
1155                 T* pT = static_cast<T*>(this);
1156                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1157                 pfd;   // avoid level 4 warning
1158                 return pT->OnTypeChange();
1159         }
1160
1161         virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse)
1162         {
1163                 T* pT = static_cast<T*>(this);
1164                 ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1165                 pfd;   // avoid level 4 warning
1166                 return pT->OnOverwrite(psi, pResponse);
1167         }
1168
1169 // Overrideables - Event handlers
1170         HRESULT OnFileOk()
1171         {
1172                 return E_NOTIMPL;
1173         }
1174
1175         HRESULT OnFolderChanging(IShellItem* /*psiFolder*/)
1176         {
1177                 return E_NOTIMPL;
1178         }
1179
1180         HRESULT OnFolderChange()
1181         {
1182                 return E_NOTIMPL;
1183         }
1184
1185         HRESULT OnSelectionChange()
1186         {
1187                 return E_NOTIMPL;
1188         }
1189
1190         HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/)
1191         {
1192                 return E_NOTIMPL;
1193         }
1194
1195         HRESULT OnTypeChange()
1196         {
1197                 return E_NOTIMPL;
1198         }
1199
1200         HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/)
1201         {
1202                 return E_NOTIMPL;
1203         }
1204 };
1205
1206
1207 ///////////////////////////////////////////////////////////////////////////////
1208 // CShellFileOpenDialogImpl - implements new Shell File Open dialog
1209
1210 template <class T>
1211 class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T >
1212 {
1213 public:
1214         ATL::CComPtr<IFileOpenDialog> m_spFileDlg;
1215
1216         CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL, 
1217                                  DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, 
1218                                  LPCWSTR lpszDefExt = NULL, 
1219                                  const COMDLG_FILTERSPEC* arrFilterSpec = NULL, 
1220                                  UINT uFilterSpecCount = 0U)
1221         {
1222                 HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog);
1223
1224                 if(SUCCEEDED(hRet))
1225                         _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
1226         }
1227
1228         IFileOpenDialog* GetPtr()
1229         {
1230                 return m_spFileDlg;
1231         }
1232 };
1233
1234
1235 ///////////////////////////////////////////////////////////////////////////////
1236 // CShellFileOpenDialog - new Shell File Open dialog without events
1237
1238 class CShellFileOpenDialog : public CShellFileOpenDialogImpl<CShellFileOpenDialog>
1239 {
1240 public:
1241         CShellFileOpenDialog(LPCWSTR lpszFileName = NULL, 
1242                              DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, 
1243                              LPCWSTR lpszDefExt = NULL, 
1244                              const COMDLG_FILTERSPEC* arrFilterSpec = NULL, 
1245                              UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl<CShellFileOpenDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
1246         { }
1247
1248 // Implementation (remove _Advise/_Unadvise code using template magic)
1249         void _Advise(DWORD& /*dwCookie*/)
1250         { }
1251
1252         void _Unadvise(DWORD /*dwCookie*/)
1253         { }
1254 };
1255
1256
1257 ///////////////////////////////////////////////////////////////////////////////
1258 // CShellFileSaveDialogImpl - implements new Shell File Save dialog
1259
1260 template <class T>
1261 class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T >
1262 {
1263 public:
1264         ATL::CComPtr<IFileSaveDialog> m_spFileDlg;
1265
1266         CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL, 
1267                                  DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, 
1268                                  LPCWSTR lpszDefExt = NULL, 
1269                                  const COMDLG_FILTERSPEC* arrFilterSpec = NULL, 
1270                                  UINT uFilterSpecCount = 0U)
1271         {
1272                 HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog);
1273
1274                 if(SUCCEEDED(hRet))
1275                         _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
1276         }
1277
1278         IFileSaveDialog* GetPtr()
1279         {
1280                 return m_spFileDlg;
1281         }
1282 };
1283
1284
1285 ///////////////////////////////////////////////////////////////////////////////
1286 // CShellFileSaveDialog - new Shell File Save dialog without events
1287
1288 class CShellFileSaveDialog : public CShellFileSaveDialogImpl<CShellFileSaveDialog>
1289 {
1290 public:
1291         CShellFileSaveDialog(LPCWSTR lpszFileName = NULL, 
1292                              DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, 
1293                              LPCWSTR lpszDefExt = NULL, 
1294                              const COMDLG_FILTERSPEC* arrFilterSpec = NULL, 
1295                              UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl<CShellFileSaveDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
1296         { }
1297
1298 // Implementation (remove _Advise/_Unadvise code using template magic)
1299         void _Advise(DWORD& /*dwCookie*/)
1300         { }
1301
1302         void _Unadvise(DWORD /*dwCookie*/)
1303         { }
1304 };
1305
1306 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
1307
1308
1309 ///////////////////////////////////////////////////////////////////////////////
1310 // CFolderDialogImpl - used for browsing for a folder
1311
1312 #ifndef _WIN32_WCE
1313
1314 template <class T>
1315 class ATL_NO_VTABLE CFolderDialogImpl
1316 {
1317 public:
1318         BROWSEINFO m_bi;
1319         LPCTSTR m_lpstrInitialFolder;
1320         LPCITEMIDLIST m_pidlInitialSelection;
1321         bool m_bExpandInitialSelection;
1322         TCHAR m_szFolderDisplayName[MAX_PATH];
1323         TCHAR m_szFolderPath[MAX_PATH];
1324         LPITEMIDLIST m_pidlSelected;
1325         HWND m_hWnd;   // used only in the callback function
1326
1327 // Constructor
1328         CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : 
1329                         m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL)
1330         {
1331                 memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL
1332
1333                 m_bi.hwndOwner = hWndParent;
1334                 m_bi.pidlRoot = NULL;
1335                 m_bi.pszDisplayName = m_szFolderDisplayName;
1336                 m_bi.lpszTitle = lpstrTitle;
1337                 m_bi.ulFlags = uFlags;
1338                 m_bi.lpfn = BrowseCallbackProc;
1339                 m_bi.lParam = (LPARAM)static_cast<T*>(this);
1340
1341                 m_szFolderPath[0] = 0;
1342                 m_szFolderDisplayName[0] = 0;
1343         }
1344
1345         ~CFolderDialogImpl()
1346         {
1347                 ::CoTaskMemFree(m_pidlSelected);
1348         }
1349
1350 // Operations
1351         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
1352         {
1353                 if(m_bi.hwndOwner == NULL)   // set only if not specified before
1354                         m_bi.hwndOwner = hWndParent;
1355
1356                 // Clear out any previous results
1357                 m_szFolderPath[0] = 0;
1358                 m_szFolderDisplayName[0] = 0;
1359                 ::CoTaskMemFree(m_pidlSelected);
1360
1361                 INT_PTR nRet = IDCANCEL;
1362                 m_pidlSelected = ::SHBrowseForFolder(&m_bi);
1363
1364                 if(m_pidlSelected != NULL)
1365                 {
1366                         nRet = IDOK;
1367
1368                         // If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path.
1369                         // Otherwise, the caller must handle the ID-list directly.
1370                         if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0)
1371                         {
1372                                 if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE)
1373                                         nRet = IDCANCEL;
1374                         }
1375                 }
1376
1377                 return nRet;
1378         }
1379
1380         // Methods to call before DoModal
1381         void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true)
1382         {
1383                 // lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified
1384                 m_lpstrInitialFolder = lpstrInitialFolder;
1385                 m_bExpandInitialSelection = bExpand;
1386         }
1387
1388         void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true)
1389         {
1390                 m_pidlInitialSelection = pidl;
1391                 m_bExpandInitialSelection = bExpand;
1392         }
1393
1394         // Methods to call after DoModal
1395         LPITEMIDLIST GetSelectedItem(bool bDetach = false)
1396         {
1397                 LPITEMIDLIST pidl = m_pidlSelected;
1398                 if(bDetach)
1399                         m_pidlSelected = NULL;
1400
1401                 return pidl;
1402         }
1403
1404         LPCTSTR GetFolderPath() const
1405         {
1406                 return m_szFolderPath;
1407         }
1408
1409         LPCTSTR GetFolderDisplayName() const
1410         {
1411                 return m_szFolderDisplayName;
1412         }
1413
1414         int GetFolderImageIndex() const
1415         {
1416                 return m_bi.iImage;
1417         }
1418
1419 // Callback function and overrideables
1420         static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
1421         {
1422 #ifndef BFFM_VALIDATEFAILED
1423   #ifdef UNICODE
1424                 const int BFFM_VALIDATEFAILED = 4;
1425   #else
1426                 const int BFFM_VALIDATEFAILED = 3;
1427   #endif
1428 #endif // !BFFM_VALIDATEFAILED
1429 #ifndef BFFM_IUNKNOWN
1430                 const int BFFM_IUNKNOWN = 5;
1431 #endif // !BFFM_IUNKNOWN
1432 #ifndef BIF_NEWDIALOGSTYLE
1433                 const UINT BIF_NEWDIALOGSTYLE = 0x0040;
1434 #endif // !BIF_NEWDIALOGSTYLE
1435
1436                 int nRet = 0;
1437                 T* pT = (T*)lpData;
1438                 bool bClear = false;
1439                 if(pT->m_hWnd == NULL)
1440                 {
1441                         pT->m_hWnd = hWnd;
1442                         bClear = true;
1443                 }
1444                 else
1445                 {
1446                         ATLASSERT(pT->m_hWnd == hWnd);
1447                 }
1448
1449                 switch(uMsg)
1450                 {
1451                 case BFFM_INITIALIZED:
1452                         // Set initial selection
1453                         // Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder
1454                         if(pT->m_pidlInitialSelection != NULL)
1455                                 pT->SetSelection(pT->m_pidlInitialSelection);
1456                         else if(pT->m_lpstrInitialFolder != NULL)
1457                                 pT->SetSelection(pT->m_lpstrInitialFolder);
1458
1459                         // Expand initial selection if appropriate
1460                         if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0))
1461                         {
1462                                 if(pT->m_pidlInitialSelection != NULL)
1463                                         pT->SetExpanded(pT->m_pidlInitialSelection);
1464                                 else if(pT->m_lpstrInitialFolder != NULL)
1465                                         pT->SetExpanded(pT->m_lpstrInitialFolder);
1466                         }
1467                         pT->OnInitialized();
1468                         break;
1469                 case BFFM_SELCHANGED:
1470                         pT->OnSelChanged((LPITEMIDLIST)lParam);
1471                         break;
1472                 case BFFM_VALIDATEFAILED:
1473                         nRet = pT->OnValidateFailed((LPCTSTR)lParam);
1474                         break;
1475                 case BFFM_IUNKNOWN:
1476                         pT->OnIUnknown((IUnknown*)lParam);
1477                         break;
1478                 default:
1479                         ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n"));
1480                         break;
1481                 }
1482
1483                 if(bClear)
1484                         pT->m_hWnd = NULL;
1485                 return nRet;
1486         }
1487
1488         void OnInitialized()
1489         {
1490         }
1491
1492         void OnSelChanged(LPITEMIDLIST /*pItemIDList*/)
1493         {
1494         }
1495
1496         int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/)
1497         {
1498                 return 1;   // 1=continue, 0=EndDialog
1499         }
1500
1501         void OnIUnknown(IUnknown* /*pUnknown*/)
1502         {
1503         }
1504
1505         // Commands - valid to call only from handlers
1506         void EnableOK(BOOL bEnable)
1507         {
1508                 ATLASSERT(m_hWnd != NULL);
1509                 ::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable);
1510         }
1511
1512         void SetSelection(LPCITEMIDLIST pItemIDList)
1513         {
1514                 ATLASSERT(m_hWnd != NULL);
1515                 ::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList);
1516         }
1517
1518         void SetSelection(LPCTSTR lpstrFolderPath)
1519         {
1520                 ATLASSERT(m_hWnd != NULL);
1521                 ::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath);
1522         }
1523
1524         void SetStatusText(LPCTSTR lpstrText)
1525         {
1526                 ATLASSERT(m_hWnd != NULL);
1527                 ::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText);
1528         }
1529
1530         void SetOKText(LPCTSTR lpstrOKText)
1531         {
1532 #ifndef BFFM_SETOKTEXT
1533                 const UINT BFFM_SETOKTEXT = WM_USER + 105;
1534 #endif
1535                 ATLASSERT(m_hWnd != NULL);
1536                 USES_CONVERSION;
1537                 LPCWSTR lpstr = T2CW(lpstrOKText);
1538                 ::SendMessage(m_hWnd, BFFM_SETOKTEXT, (WPARAM)lpstr, 0L);
1539         }
1540
1541         void SetExpanded(LPCITEMIDLIST pItemIDList)
1542         {
1543 #ifndef BFFM_SETEXPANDED
1544                 const UINT BFFM_SETEXPANDED = WM_USER + 106;
1545 #endif
1546                 ATLASSERT(m_hWnd != NULL);
1547                 ::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList);
1548         }
1549
1550         void SetExpanded(LPCTSTR lpstrFolderPath)
1551         {
1552 #ifndef BFFM_SETEXPANDED
1553                 const UINT BFFM_SETEXPANDED = WM_USER + 106;
1554 #endif
1555                 ATLASSERT(m_hWnd != NULL);
1556                 USES_CONVERSION;
1557                 LPCWSTR lpstr = T2CW(lpstrFolderPath);
1558                 ::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr);
1559         }
1560 };
1561
1562 class CFolderDialog : public CFolderDialogImpl<CFolderDialog>
1563 {
1564 public:
1565         CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS)
1566                 : CFolderDialogImpl<CFolderDialog>(hWndParent, lpstrTitle, uFlags)
1567         { }
1568 };
1569
1570 #endif // !_WIN32_WCE
1571
1572
1573 ///////////////////////////////////////////////////////////////////////////////
1574 // CCommonDialogImplBase - base class for common dialog classes
1575
1576 class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase
1577 {
1578 public:
1579         static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1580         {
1581                 if(uMsg != WM_INITDIALOG)
1582                         return 0;
1583                 CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
1584                 ATLASSERT(pT != NULL);
1585                 ATLASSERT(pT->m_hWnd == NULL);
1586                 ATLASSERT(::IsWindow(hWnd));
1587                 // subclass dialog's window
1588                 if(!pT->SubclassWindow(hWnd))
1589                 {
1590                         ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n"));
1591                         return 0;
1592                 }
1593                 // check message map for WM_INITDIALOG handler
1594                 LRESULT lRes = 0;
1595                 if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
1596                         return 0;
1597                 return lRes;
1598         }
1599
1600 // Special override for common dialogs
1601         BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
1602         {
1603                 ATLASSERT(::IsWindow(m_hWnd));
1604                 SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
1605                 return TRUE;
1606         }
1607
1608 // Implementation - try to override these, to prevent errors
1609         HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID)
1610         {
1611                 ATLASSERT(FALSE);   // should not be called
1612                 return NULL;
1613         }
1614
1615         static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
1616         {
1617                 ATLASSERT(FALSE);   // should not be called
1618                 return 0;
1619         }
1620 };
1621
1622
1623 ///////////////////////////////////////////////////////////////////////////////
1624 // CFontDialogImpl - font selection dialog
1625
1626 #ifndef _WIN32_WCE
1627
1628 template <class T>
1629 class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase
1630 {
1631 public:
1632         enum { _cchStyleName = 64 };
1633
1634         CHOOSEFONT m_cf;
1635         TCHAR m_szStyleName[_cchStyleName];  // contains style name after return
1636         LOGFONT m_lf;                        // default LOGFONT to store the info
1637
1638 // Constructors
1639         CFontDialogImpl(LPLOGFONT lplfInitial = NULL,
1640                         DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
1641                         HDC hDCPrinter = NULL,
1642                         HWND hWndParent = NULL)
1643         {
1644                 memset(&m_cf, 0, sizeof(m_cf));
1645                 memset(&m_lf, 0, sizeof(m_lf));
1646                 memset(&m_szStyleName, 0, sizeof(m_szStyleName));
1647
1648                 m_cf.lStructSize = sizeof(m_cf);
1649                 m_cf.hwndOwner = hWndParent;
1650                 m_cf.rgbColors = RGB(0, 0, 0);
1651                 m_cf.lpszStyle = (LPTSTR)&m_szStyleName;
1652                 m_cf.Flags = dwFlags | CF_ENABLEHOOK;
1653                 m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc;
1654
1655                 if(lplfInitial != NULL)
1656                 {
1657                         m_cf.lpLogFont = lplfInitial;
1658                         m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1659                         m_lf = *lplfInitial;
1660                 }
1661                 else
1662                 {
1663                         m_cf.lpLogFont = &m_lf;
1664                 }
1665
1666                 if(hDCPrinter != NULL)
1667                 {
1668                         m_cf.hDC = hDCPrinter;
1669                         m_cf.Flags |= CF_PRINTERFONTS;
1670                 }
1671         }
1672
1673 // Operations
1674         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
1675         {
1676                 ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0);
1677                 ATLASSERT(m_cf.lpfnHook != NULL);   // can still be a user hook
1678
1679                 if(m_cf.hwndOwner == NULL)          // set only if not specified before
1680                         m_cf.hwndOwner = hWndParent;
1681
1682                 ATLASSERT(m_hWnd == NULL);
1683                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
1684
1685                 BOOL bRet = ::ChooseFont(&m_cf);
1686
1687                 m_hWnd = NULL;
1688
1689                 if(bRet)   // copy logical font from user's initialization buffer (if needed)
1690                         SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf));
1691
1692                 return bRet ? IDOK : IDCANCEL;
1693         }
1694
1695         // works only when the dialog is dislayed or after
1696         void GetCurrentFont(LPLOGFONT lplf) const
1697         {
1698                 ATLASSERT(lplf != NULL);
1699
1700                 if(m_hWnd != NULL)
1701                         ::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf);
1702                 else
1703                         *lplf = m_lf;
1704         }
1705
1706         // works only when the dialog is dislayed or before
1707 #ifndef _WIN32_WCE
1708         void SetLogFont(LPLOGFONT lplf)
1709         {
1710                 ATLASSERT(lplf != NULL);
1711 #ifndef WM_CHOOSEFONT_SETLOGFONT
1712                 const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101);
1713 #endif
1714                 if(m_hWnd != NULL)
1715                 {
1716                         ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf);
1717                 }
1718                 else
1719                 {
1720                         m_lf = *lplf;
1721                         m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1722                 }
1723         }
1724
1725         void SetFlags(DWORD dwFlags)
1726         {
1727 #ifndef WM_CHOOSEFONT_SETFLAGS
1728                 const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102);
1729 #endif
1730                 if(m_hWnd != NULL)
1731                 {
1732                         CHOOSEFONT cf = { sizeof(CHOOSEFONT) };
1733                         cf.Flags = dwFlags;
1734                         ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf);
1735                 }
1736                 else
1737                 {
1738                         m_cf.Flags = dwFlags;
1739                 }
1740         }
1741 #endif // !_WIN32_WCE
1742
1743         // Helpers for parsing information after successful return
1744         LPCTSTR GetFaceName() const   // return the face name of the font
1745         {
1746                 return (LPCTSTR)m_cf.lpLogFont->lfFaceName;
1747         }
1748
1749         LPCTSTR GetStyleName() const  // return the style name of the font
1750         {
1751                 return m_cf.lpszStyle;
1752         }
1753
1754         int GetSize() const           // return the pt size of the font
1755         {
1756                 return m_cf.iPointSize;
1757         }
1758
1759         COLORREF GetColor() const     // return the color of the font
1760         {
1761                 return m_cf.rgbColors;
1762         }
1763
1764         int GetWeight() const         // return the chosen font weight
1765         {
1766                 return (int)m_cf.lpLogFont->lfWeight;
1767         }
1768
1769         BOOL IsStrikeOut() const      // return TRUE if strikeout
1770         {
1771                 return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE;
1772         }
1773
1774         BOOL IsUnderline() const      // return TRUE if underline
1775         {
1776                 return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE;
1777         }
1778
1779         BOOL IsBold() const           // return TRUE if bold font
1780         {
1781                 return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE;
1782         }
1783
1784         BOOL IsItalic() const         // return TRUE if italic font
1785         {
1786                 return m_cf.lpLogFont->lfItalic ? TRUE : FALSE;
1787         }
1788 };
1789
1790 class CFontDialog : public CFontDialogImpl<CFontDialog>
1791 {
1792 public:
1793         CFontDialog(LPLOGFONT lplfInitial = NULL,
1794                 DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
1795                 HDC hDCPrinter = NULL,
1796                 HWND hWndParent = NULL)
1797                 : CFontDialogImpl<CFontDialog>(lplfInitial, dwFlags, hDCPrinter, hWndParent)
1798         { }
1799
1800         DECLARE_EMPTY_MSG_MAP()
1801 };
1802
1803 #endif // _WIN32_WCE
1804
1805
1806 ///////////////////////////////////////////////////////////////////////////////
1807 // CRichEditFontDialogImpl - font selection for the Rich Edit ctrl
1808
1809 #if defined(_RICHEDIT_) && !defined(_WIN32_WCE)
1810
1811 template <class T>
1812 class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T >
1813 {
1814 public:
1815         CRichEditFontDialogImpl(const CHARFORMAT& charformat,
1816                         DWORD dwFlags = CF_SCREENFONTS,
1817                         HDC hDCPrinter = NULL,
1818                         HWND hWndParent = NULL)
1819                         : CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent)
1820         {
1821                 m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1822                 m_cf.Flags |= FillInLogFont(charformat);
1823                 m_cf.lpLogFont = &m_lf;
1824
1825                 if((charformat.dwMask & CFM_COLOR) != 0)
1826                         m_cf.rgbColors = charformat.crTextColor;
1827         }
1828
1829         void GetCharFormat(CHARFORMAT& cf) const
1830         {
1831                 USES_CONVERSION;
1832                 cf.dwEffects = 0;
1833                 cf.dwMask = 0;
1834                 if((m_cf.Flags & CF_NOSTYLESEL) == 0)
1835                 {
1836                         cf.dwMask |= CFM_BOLD | CFM_ITALIC;
1837                         cf.dwEffects |= IsBold() ? CFE_BOLD : 0;
1838                         cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0;
1839                 }
1840                 if((m_cf.Flags & CF_NOSIZESEL) == 0)
1841                 {
1842                         cf.dwMask |= CFM_SIZE;
1843                         // GetSize() returns in tenths of points so mulitply by 2 to get twips
1844                         cf.yHeight = GetSize() * 2;
1845                 }
1846
1847                 if((m_cf.Flags & CF_NOFACESEL) == 0)
1848                 {
1849                         cf.dwMask |= CFM_FACE;
1850                         cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily;
1851 #if (_RICHEDIT_VER >= 0x0200)
1852                         SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName());
1853 #else // !(_RICHEDIT_VER >= 0x0200)
1854                         SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName()));
1855 #endif // !(_RICHEDIT_VER >= 0x0200)
1856                 }
1857
1858                 if((m_cf.Flags & CF_EFFECTS) != 0)
1859                 {
1860                         cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
1861                         cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0;
1862                         cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0;
1863                         cf.crTextColor = GetColor();
1864                 }
1865                 if((m_cf.Flags & CF_NOSCRIPTSEL) == 0)
1866                 {
1867                         cf.bCharSet = m_cf.lpLogFont->lfCharSet;
1868                         cf.dwMask |= CFM_CHARSET;
1869                 }
1870                 cf.yOffset = 0;
1871         }
1872
1873         DWORD FillInLogFont(const CHARFORMAT& cf)
1874         {
1875                 USES_CONVERSION;
1876                 DWORD dwFlags = 0;
1877                 if((cf.dwMask & CFM_SIZE) != 0)
1878                 {
1879                         HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
1880                         LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY);
1881                         m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440);
1882                 }
1883                 else
1884                         m_lf.lfHeight = 0;
1885
1886                 m_lf.lfWidth = 0;
1887                 m_lf.lfEscapement = 0;
1888                 m_lf.lfOrientation = 0;
1889
1890                 if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD))
1891                 {
1892                         m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL;
1893                         m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE);
1894                 }
1895                 else
1896                 {
1897                         dwFlags |= CF_NOSTYLESEL;
1898                         m_lf.lfWeight = FW_DONTCARE;
1899                         m_lf.lfItalic = FALSE;
1900                 }
1901
1902                 if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR))
1903                 {
1904                         dwFlags |= CF_EFFECTS;
1905                         m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE);
1906                         m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE);
1907                 }
1908                 else
1909                 {
1910                         m_lf.lfUnderline = (BYTE)FALSE;
1911                         m_lf.lfStrikeOut = (BYTE)FALSE;
1912                 }
1913
1914                 if((cf.dwMask & CFM_CHARSET) != 0)
1915                         m_lf.lfCharSet = cf.bCharSet;
1916                 else
1917                         dwFlags |= CF_NOSCRIPTSEL;
1918                 m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1919                 m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1920                 m_lf.lfQuality = DEFAULT_QUALITY;
1921                 if((cf.dwMask & CFM_FACE) != 0)
1922                 {
1923                         m_lf.lfPitchAndFamily = cf.bPitchAndFamily;
1924 #if (_RICHEDIT_VER >= 0x0200)
1925                         SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName);
1926 #else // !(_RICHEDIT_VER >= 0x0200)
1927                         SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName));
1928 #endif // !(_RICHEDIT_VER >= 0x0200)
1929                 }
1930                 else
1931                 {
1932                         m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
1933                         m_lf.lfFaceName[0] = (TCHAR)0;
1934                 }
1935                 return dwFlags;
1936         }
1937 };
1938
1939 class CRichEditFontDialog : public CRichEditFontDialogImpl<CRichEditFontDialog>
1940 {
1941 public:
1942         CRichEditFontDialog(const CHARFORMAT& charformat,
1943                 DWORD dwFlags = CF_SCREENFONTS,
1944                 HDC hDCPrinter = NULL,
1945                 HWND hWndParent = NULL)
1946                 : CRichEditFontDialogImpl<CRichEditFontDialog>(charformat, dwFlags, hDCPrinter, hWndParent)
1947         { }
1948
1949         DECLARE_EMPTY_MSG_MAP()
1950 };
1951
1952 #endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE)
1953
1954
1955 ///////////////////////////////////////////////////////////////////////////////
1956 // CColorDialogImpl - color selection
1957
1958 #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
1959
1960 #ifdef _WIN32_WCE
1961   #pragma comment(lib, "commdlg.lib")
1962
1963   #ifndef SETRGBSTRING
1964     #define SETRGBSTRING _T("commdlg_SetRGBColor")
1965   #endif
1966
1967   #ifndef COLOROKSTRING
1968     #define COLOROKSTRING _T("commdlg_ColorOK")
1969   #endif
1970 #endif
1971
1972 template <class T>
1973 class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase
1974 {
1975 public:
1976         CHOOSECOLOR m_cc;
1977
1978 // Constructor
1979         CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
1980         {
1981                 memset(&m_cc, 0, sizeof(m_cc));
1982
1983                 m_cc.lStructSize = sizeof(m_cc);
1984                 m_cc.lpCustColors = GetCustomColors();
1985                 m_cc.hwndOwner = hWndParent;
1986                 m_cc.Flags = dwFlags | CC_ENABLEHOOK;
1987                 m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc;
1988
1989                 if(clrInit != 0)
1990                 {
1991                         m_cc.rgbResult = clrInit;
1992                         m_cc.Flags |= CC_RGBINIT;
1993                 }
1994         }
1995
1996 // Operations
1997         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
1998         {
1999                 ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0);
2000                 ATLASSERT(m_cc.lpfnHook != NULL);   // can still be a user hook
2001
2002                 if(m_cc.hwndOwner == NULL)          // set only if not specified before
2003                         m_cc.hwndOwner = hWndParent;
2004
2005                 ATLASSERT(m_hWnd == NULL);
2006                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2007
2008                 BOOL bRet = ::ChooseColor(&m_cc);
2009
2010                 m_hWnd = NULL;
2011
2012                 return bRet ? IDOK : IDCANCEL;
2013         }
2014
2015         // Set the current color while dialog is displayed
2016         void SetCurrentColor(COLORREF clr)
2017         {
2018                 ATLASSERT(::IsWindow(m_hWnd));
2019                 SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr);
2020         }
2021
2022         // Get the selected color after DoModal returns, or in OnColorOK
2023         COLORREF GetColor() const
2024         {
2025                 return m_cc.rgbResult;
2026         }
2027
2028 // Special override for the color dialog
2029         static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2030         {
2031                 if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage())
2032                         return 0;
2033
2034                 LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam;
2035                 CCommonDialogImplBase* pT = NULL;
2036
2037                 if(uMsg == WM_INITDIALOG)
2038                 {
2039                         pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
2040                         lpCC->lCustData = (LPARAM)pT;
2041                         ATLASSERT(pT != NULL);
2042                         ATLASSERT(pT->m_hWnd == NULL);
2043                         ATLASSERT(::IsWindow(hWnd));
2044                         // subclass dialog's window
2045                         if(!pT->SubclassWindow(hWnd))
2046                         {
2047                                 ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n"));
2048                                 return 0;
2049                         }
2050                 }
2051                 else if(uMsg == _GetColorOKMessage())
2052                 {
2053                         pT = (CCommonDialogImplBase*)lpCC->lCustData;
2054                         ATLASSERT(pT != NULL);
2055                         ATLASSERT(::IsWindow(pT->m_hWnd));
2056                 }
2057
2058                 // pass to the message map
2059                 LRESULT lRes;
2060                 if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
2061                         return 0;
2062                 return lRes;
2063         }
2064
2065 // Helpers
2066         static COLORREF* GetCustomColors()
2067         {
2068                 static COLORREF rgbCustomColors[16] =
2069                 {
2070                         RGB(255, 255, 255), RGB(255, 255, 255), 
2071                         RGB(255, 255, 255), RGB(255, 255, 255), 
2072                         RGB(255, 255, 255), RGB(255, 255, 255), 
2073                         RGB(255, 255, 255), RGB(255, 255, 255), 
2074                         RGB(255, 255, 255), RGB(255, 255, 255), 
2075                         RGB(255, 255, 255), RGB(255, 255, 255), 
2076                         RGB(255, 255, 255), RGB(255, 255, 255), 
2077                         RGB(255, 255, 255), RGB(255, 255, 255), 
2078                 };
2079
2080                 return rgbCustomColors;
2081         }
2082
2083         static UINT _GetSetRGBMessage()
2084         {
2085                 static UINT uSetRGBMessage = 0;
2086                 if(uSetRGBMessage == 0)
2087                 {
2088                         CStaticDataInitCriticalSectionLock lock;
2089                         if(FAILED(lock.Lock()))
2090                         {
2091                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n"));
2092                                 ATLASSERT(FALSE);
2093                                 return 0;
2094                         }
2095
2096                         if(uSetRGBMessage == 0)
2097                                 uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING);
2098
2099                         lock.Unlock();
2100                 }
2101                 ATLASSERT(uSetRGBMessage != 0);
2102                 return uSetRGBMessage;
2103         }
2104
2105         static UINT _GetColorOKMessage()
2106         {
2107                 static UINT uColorOKMessage = 0;
2108                 if(uColorOKMessage == 0)
2109                 {
2110                         CStaticDataInitCriticalSectionLock lock;
2111                         if(FAILED(lock.Lock()))
2112                         {
2113                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n"));
2114                                 ATLASSERT(FALSE);
2115                                 return 0;
2116                         }
2117
2118                         if(uColorOKMessage == 0)
2119                                 uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING);
2120
2121                         lock.Unlock();
2122                 }
2123                 ATLASSERT(uColorOKMessage != 0);
2124                 return uColorOKMessage;
2125         }
2126
2127 // Message map and handlers
2128         BEGIN_MSG_MAP(CColorDialogImpl)
2129                 MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK)
2130         END_MSG_MAP()
2131
2132         LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&)
2133         {
2134                 T* pT = static_cast<T*>(this);
2135                 return pT->OnColorOK();
2136         }
2137
2138 // Overrideable
2139         BOOL OnColorOK()        // validate color
2140         {
2141                 return FALSE;
2142         }
2143 };
2144
2145 class CColorDialog : public CColorDialogImpl<CColorDialog>
2146 {
2147 public:
2148         CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
2149                 : CColorDialogImpl<CColorDialog>(clrInit, dwFlags, hWndParent)
2150         { }
2151
2152         // override base class map and references to handlers
2153         DECLARE_EMPTY_MSG_MAP()
2154 };
2155
2156 #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
2157
2158
2159 ///////////////////////////////////////////////////////////////////////////////
2160 // CPrintDialogImpl - used for Print... and PrintSetup...
2161
2162 #ifndef _WIN32_WCE
2163
2164 // global helper
2165 static HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode)
2166 {
2167         if(hDevNames == NULL)
2168                 return NULL;
2169
2170         LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames);
2171         LPDEVMODE  lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL;
2172
2173         if(lpDevNames == NULL)
2174                 return NULL;
2175
2176         HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset,
2177                                           (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset,
2178                                           (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset,
2179                                           lpDevMode);
2180
2181         ::GlobalUnlock(hDevNames);
2182         if(hDevMode != NULL)
2183                 ::GlobalUnlock(hDevMode);
2184         return hDC;
2185 }
2186
2187 template <class T>
2188 class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase
2189 {
2190 public:
2191         // print dialog parameter block (note this is a reference)
2192         PRINTDLG& m_pd;
2193
2194 // Constructors
2195         CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE,  // TRUE for Print Setup, FALSE for Print Dialog
2196                         DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
2197                         HWND hWndParent = NULL)
2198                         : m_pd(m_pdActual)
2199         {
2200                 memset(&m_pdActual, 0, sizeof(m_pdActual));
2201
2202                 m_pd.lStructSize = sizeof(m_pdActual);
2203                 m_pd.hwndOwner = hWndParent;
2204                 m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);
2205                 m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc;
2206                 m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc;
2207
2208                 if(bPrintSetupOnly)
2209                         m_pd.Flags |= PD_PRINTSETUP;
2210                 else
2211                         m_pd.Flags |= PD_RETURNDC;
2212
2213                 m_pd.Flags &= ~PD_RETURNIC; // do not support information context
2214         }
2215
2216 // Operations
2217         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
2218         {
2219                 ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0);
2220                 ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0);
2221                 ATLASSERT(m_pd.lpfnPrintHook != NULL);   // can still be a user hook
2222                 ATLASSERT(m_pd.lpfnSetupHook != NULL);   // can still be a user hook
2223                 ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this
2224
2225                 if(m_pd.hwndOwner == NULL)   // set only if not specified before
2226                         m_pd.hwndOwner = hWndParent;
2227
2228                 ATLASSERT(m_hWnd == NULL);
2229                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2230
2231                 BOOL bRet = ::PrintDlg(&m_pd);
2232
2233                 m_hWnd = NULL;
2234
2235                 return bRet ? IDOK : IDCANCEL;
2236         }
2237
2238         // GetDefaults will not display a dialog but will get device defaults
2239         BOOL GetDefaults()
2240         {
2241                 m_pd.Flags |= PD_RETURNDEFAULT;
2242                 ATLASSERT(m_pd.hDevMode == NULL);    // must be NULL
2243                 ATLASSERT(m_pd.hDevNames == NULL);   // must be NULL
2244
2245                 return ::PrintDlg(&m_pd);
2246         }
2247
2248         // Helpers for parsing information after successful return num. copies requested
2249         int GetCopies() const
2250         {
2251                 if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0)
2252                 {
2253                         LPDEVMODE lpDevMode = GetDevMode();
2254                         return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
2255                 }
2256
2257                 return m_pd.nCopies;
2258         }
2259
2260         BOOL PrintCollate() const       // TRUE if collate checked
2261         {
2262                 return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
2263         }
2264
2265         BOOL PrintSelection() const     // TRUE if printing selection
2266         {
2267                 return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
2268         }
2269
2270         BOOL PrintAll() const           // TRUE if printing all pages
2271         {
2272                 return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
2273         }
2274
2275         BOOL PrintRange() const         // TRUE if printing page range
2276         {
2277                 return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
2278         }
2279
2280         BOOL PrintToFile() const        // TRUE if printing to a file
2281         {
2282                 return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
2283         }
2284
2285         int GetFromPage() const         // starting page if valid
2286         {
2287                 return PrintRange() ? m_pd.nFromPage : -1;
2288         }
2289
2290         int GetToPage() const           // ending page if valid
2291         {
2292                 return PrintRange() ? m_pd.nToPage : -1;
2293         }
2294
2295         LPDEVMODE GetDevMode() const    // return DEVMODE
2296         {
2297                 if(m_pd.hDevMode == NULL)
2298                         return NULL;
2299
2300                 return (LPDEVMODE)::GlobalLock(m_pd.hDevMode);
2301         }
2302
2303         LPCTSTR GetDriverName() const   // return driver name
2304         {
2305                 if(m_pd.hDevNames == NULL)
2306                         return NULL;
2307
2308                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2309                 if(lpDev == NULL)
2310                         return NULL;
2311
2312                 return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2313         }
2314
2315         LPCTSTR GetDeviceName() const   // return device name
2316         {
2317                 if(m_pd.hDevNames == NULL)
2318                         return NULL;
2319
2320                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2321                 if(lpDev == NULL)
2322                         return NULL;
2323
2324                 return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2325         }
2326
2327         LPCTSTR GetPortName() const     // return output port name
2328         {
2329                 if(m_pd.hDevNames == NULL)
2330                         return NULL;
2331
2332                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2333                 if(lpDev == NULL)
2334                         return NULL;
2335
2336                 return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2337         }
2338
2339         HDC GetPrinterDC() const        // return HDC (caller must delete)
2340         {
2341                 ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0);
2342                 return m_pd.hDC;
2343         }
2344
2345         // This helper creates a DC based on the DEVNAMES and DEVMODE structures.
2346         // This DC is returned, but also stored in m_pd.hDC as though it had been
2347         // returned by CommDlg.  It is assumed that any previously obtained DC
2348         // has been/will be deleted by the user.  This may be
2349         // used without ever invoking the print/print setup dialogs.
2350         HDC CreatePrinterDC()
2351         {
2352                 m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode);
2353                 return m_pd.hDC;
2354         }
2355
2356 // Implementation
2357         PRINTDLG m_pdActual; // the Print/Print Setup need to share this
2358
2359         // The following handle the case of print setup... from the print dialog
2360         CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit)
2361         { }
2362
2363         BEGIN_MSG_MAP(CPrintDialogImpl)
2364 #ifdef psh1
2365                 COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed
2366 #else // !psh1
2367                 COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h
2368 #endif // !psh1
2369         END_MSG_MAP()
2370
2371         LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
2372         {
2373                 T dlgSetup(m_pd);
2374                 ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);
2375                 return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl);
2376         }
2377 };
2378
2379 class CPrintDialog : public CPrintDialogImpl<CPrintDialog>
2380 {
2381 public:
2382         CPrintDialog(BOOL bPrintSetupOnly = FALSE,
2383                 DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
2384                 HWND hWndParent = NULL)
2385                 : CPrintDialogImpl<CPrintDialog>(bPrintSetupOnly, dwFlags, hWndParent)
2386         { }
2387
2388         CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl<CPrintDialog>(pdInit)
2389         { }
2390 };
2391
2392 #endif // _WIN32_WCE
2393
2394
2395 ///////////////////////////////////////////////////////////////////////////////
2396 // CPrintDialogExImpl - new print dialog for Windows 2000
2397
2398 #if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
2399
2400 }; // namespace WTL
2401
2402 #include <atlcom.h>
2403
2404 extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
2405 extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
2406
2407 namespace WTL
2408 {
2409
2410 template <class T>
2411 class ATL_NO_VTABLE CPrintDialogExImpl : 
2412                                 public ATL::CWindow,
2413                                 public ATL::CMessageMap,
2414                                 public IPrintDialogCallback,
2415                                 public ATL::IObjectWithSiteImpl< T >
2416 {
2417 public:
2418         PRINTDLGEX m_pdex;
2419
2420 // Constructor
2421         CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
2422                                 HWND hWndParent = NULL)
2423         {
2424                 memset(&m_pdex, 0, sizeof(m_pdex));
2425
2426                 m_pdex.lStructSize = sizeof(PRINTDLGEX);
2427                 m_pdex.hwndOwner = hWndParent;
2428                 m_pdex.Flags = dwFlags;
2429                 m_pdex.nStartPage = START_PAGE_GENERAL;
2430                 // callback object will be set in DoModal
2431
2432                 m_pdex.Flags &= ~PD_RETURNIC; // do not support information context
2433         }
2434
2435 // Operations
2436         HRESULT DoModal(HWND hWndParent = ::GetActiveWindow())
2437         {
2438                 ATLASSERT(m_hWnd == NULL);
2439                 ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this
2440
2441                 if(m_pdex.hwndOwner == NULL)   // set only if not specified before
2442                         m_pdex.hwndOwner = hWndParent;
2443
2444                 T* pT = static_cast<T*>(this);
2445                 m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT;
2446
2447                 HRESULT hResult = ::PrintDlgEx(&m_pdex);
2448
2449                 m_hWnd = NULL;
2450
2451                 return hResult;
2452         }
2453
2454         BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
2455         {
2456                 ATLASSERT(::IsWindow(m_hWnd));
2457                 SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
2458                 return TRUE;
2459         }
2460
2461         // GetDefaults will not display a dialog but will get device defaults
2462         HRESULT GetDefaults()
2463         {
2464                 m_pdex.Flags |= PD_RETURNDEFAULT;
2465                 ATLASSERT(m_pdex.hDevMode == NULL);    // must be NULL
2466                 ATLASSERT(m_pdex.hDevNames == NULL);   // must be NULL
2467
2468                 return ::PrintDlgEx(&m_pdex);
2469         }
2470
2471         // Helpers for parsing information after successful return num. copies requested
2472         int GetCopies() const
2473         {
2474                 if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0)
2475                 {
2476                         LPDEVMODE lpDevMode = GetDevMode();
2477                         return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
2478                 }
2479
2480                 return m_pdex.nCopies;
2481         }
2482
2483         BOOL PrintCollate() const       // TRUE if collate checked
2484         {
2485                 return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
2486         }
2487
2488         BOOL PrintSelection() const     // TRUE if printing selection
2489         {
2490                 return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
2491         }
2492
2493         BOOL PrintAll() const           // TRUE if printing all pages
2494         {
2495                 return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
2496         }
2497
2498         BOOL PrintRange() const         // TRUE if printing page range
2499         {
2500                 return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
2501         }
2502
2503         BOOL PrintToFile() const        // TRUE if printing to a file
2504         {
2505                 return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
2506         }
2507
2508         LPDEVMODE GetDevMode() const    // return DEVMODE
2509         {
2510                 if(m_pdex.hDevMode == NULL)
2511                         return NULL;
2512
2513                 return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode);
2514         }
2515
2516         LPCTSTR GetDriverName() const   // return driver name
2517         {
2518                 if(m_pdex.hDevNames == NULL)
2519                         return NULL;
2520
2521                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2522                 if(lpDev == NULL)
2523                         return NULL;
2524
2525                 return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2526         }
2527
2528         LPCTSTR GetDeviceName() const   // return device name
2529         {
2530                 if(m_pdex.hDevNames == NULL)
2531                         return NULL;
2532
2533                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2534                 if(lpDev == NULL)
2535                         return NULL;
2536
2537                 return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2538         }
2539
2540         LPCTSTR GetPortName() const     // return output port name
2541         {
2542                 if(m_pdex.hDevNames == NULL)
2543                         return NULL;
2544
2545                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2546                 if(lpDev == NULL)
2547                         return NULL;
2548
2549                 return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2550         }
2551
2552         HDC GetPrinterDC() const        // return HDC (caller must delete)
2553         {
2554                 ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0);
2555                 return m_pdex.hDC;
2556         }
2557
2558         // This helper creates a DC based on the DEVNAMES and DEVMODE structures.
2559         // This DC is returned, but also stored in m_pdex.hDC as though it had been
2560         // returned by CommDlg.  It is assumed that any previously obtained DC
2561         // has been/will be deleted by the user.  This may be
2562         // used without ever invoking the print/print setup dialogs.
2563         HDC CreatePrinterDC()
2564         {
2565                 m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode);
2566                 return m_pdex.hDC;
2567         }
2568
2569 // Implementation - interfaces
2570
2571 // IUnknown
2572         STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
2573         {
2574                 if(ppvObject == NULL)
2575                         return E_POINTER;
2576
2577                 T* pT = static_cast<T*>(this);
2578                 if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback))
2579                 {
2580                         *ppvObject = (IPrintDialogCallback*)pT;
2581                         // AddRef() not needed
2582                         return S_OK;
2583                 }
2584                 else if(IsEqualGUID(riid, IID_IObjectWithSite))
2585                 {
2586                         *ppvObject = (IObjectWithSite*)pT;
2587                         // AddRef() not needed
2588                         return S_OK;
2589                 }
2590
2591                 return E_NOINTERFACE;
2592         }
2593
2594         virtual ULONG STDMETHODCALLTYPE AddRef()
2595         {
2596                 return 1;
2597         }
2598
2599         virtual ULONG STDMETHODCALLTYPE Release()
2600         {
2601                 return 1;
2602         }
2603
2604 // IPrintDialogCallback
2605         STDMETHOD(InitDone)()
2606         {
2607                 return S_FALSE;
2608         }
2609
2610         STDMETHOD(SelectionChange)()
2611         {
2612                 return S_FALSE;
2613         }
2614
2615         STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
2616         {
2617                 // set up m_hWnd the first time
2618                 if(m_hWnd == NULL)
2619                         Attach(hWnd);
2620
2621                 // call message map
2622                 HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE;
2623                 if(hRet == S_OK && uMsg == WM_NOTIFY)   // return in DWLP_MSGRESULT
2624                         ::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult);
2625
2626                 if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE)
2627                         hRet = S_FALSE;
2628
2629                 return hRet;
2630         }
2631 };
2632
2633 class CPrintDialogEx : public CPrintDialogExImpl<CPrintDialogEx>
2634 {
2635 public:
2636         CPrintDialogEx(
2637                 DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
2638                 HWND hWndParent = NULL)
2639                 : CPrintDialogExImpl<CPrintDialogEx>(dwFlags, hWndParent)
2640         { }
2641
2642         DECLARE_EMPTY_MSG_MAP()
2643 };
2644
2645 #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
2646
2647
2648 ///////////////////////////////////////////////////////////////////////////////
2649 // CPageSetupDialogImpl - Page Setup dialog
2650
2651 #ifndef _WIN32_WCE
2652
2653 template <class T>
2654 class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase
2655 {
2656 public:
2657         PAGESETUPDLG m_psd;
2658         ATL::CWndProcThunk m_thunkPaint;
2659
2660 // Constructors
2661         CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
2662         {
2663                 memset(&m_psd, 0, sizeof(m_psd));
2664
2665                 m_psd.lStructSize = sizeof(m_psd);
2666                 m_psd.hwndOwner = hWndParent;
2667                 m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK);
2668                 m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc;
2669                 m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this);
2670 #if (_ATL_VER >= 0x0700)
2671                 m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC();
2672 #else
2673                 m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk);
2674 #endif
2675         }
2676
2677         DECLARE_EMPTY_MSG_MAP()
2678
2679 // Attributes
2680         LPDEVMODE GetDevMode() const    // return DEVMODE
2681         {
2682                 if(m_psd.hDevMode == NULL)
2683                         return NULL;
2684
2685                 return (LPDEVMODE)::GlobalLock(m_psd.hDevMode);
2686         }
2687
2688         LPCTSTR GetDriverName() const   // return driver name
2689         {
2690                 if(m_psd.hDevNames == NULL)
2691                         return NULL;
2692
2693                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2694                 return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2695         }
2696
2697         LPCTSTR GetDeviceName() const   // return device name
2698         {
2699                 if(m_psd.hDevNames == NULL)
2700                         return NULL;
2701
2702                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2703                 return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2704         }
2705
2706         LPCTSTR GetPortName() const     // return output port name
2707         {
2708                 if(m_psd.hDevNames == NULL)
2709                         return NULL;
2710
2711                 LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2712                 return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2713         }
2714
2715         HDC CreatePrinterDC()
2716         {
2717                 return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode);
2718         }
2719
2720         SIZE GetPaperSize() const
2721         {
2722                 SIZE size;
2723                 size.cx = m_psd.ptPaperSize.x;
2724                 size.cy = m_psd.ptPaperSize.y;
2725                 return size;
2726         }
2727
2728         void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const
2729         {
2730                 if(lpRectMargins != NULL)
2731                         *lpRectMargins = m_psd.rtMargin;
2732                 if(lpRectMinMargins != NULL)
2733                         *lpRectMinMargins = m_psd.rtMinMargin;
2734         }
2735
2736 // Operations
2737         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
2738         {
2739                 ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0);
2740                 ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0);
2741                 ATLASSERT(m_psd.lpfnPageSetupHook != NULL);   // can still be a user hook
2742                 ATLASSERT(m_psd.lpfnPagePaintHook != NULL);   // can still be a user hook
2743
2744                 if(m_psd.hwndOwner == NULL)   // set only if not specified before
2745                         m_psd.hwndOwner = hWndParent;
2746
2747                 ATLASSERT(m_hWnd == NULL);
2748                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2749
2750                 BOOL bRet = ::PageSetupDlg(&m_psd);
2751
2752                 m_hWnd = NULL;
2753
2754                 return bRet ? IDOK : IDCANCEL;
2755         }
2756
2757 // Implementation
2758         static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2759         {
2760                 T* pT = (T*)hWnd;
2761                 UINT_PTR uRet = 0;
2762                 switch(uMsg)
2763                 {
2764                 case WM_PSD_PAGESETUPDLG:
2765                         uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam);
2766                         break;
2767                 case WM_PSD_FULLPAGERECT:
2768                 case WM_PSD_MINMARGINRECT:
2769                 case WM_PSD_MARGINRECT:
2770                 case WM_PSD_GREEKTEXTRECT:
2771                 case WM_PSD_ENVSTAMPRECT:
2772                 case WM_PSD_YAFULLPAGERECT:
2773                         uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam);
2774                         break;
2775                 default:
2776                         ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n"));
2777                         break;
2778                 }
2779                 return uRet;
2780         }
2781
2782 // Overridables
2783         UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/)
2784         {
2785                 // return 1 to prevent any more drawing
2786                 return 0;
2787         }
2788
2789         UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/)
2790         {
2791                 return 0; // do the default
2792         }
2793 };
2794
2795 class CPageSetupDialog : public CPageSetupDialogImpl<CPageSetupDialog>
2796 {
2797 public:
2798         CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
2799                 : CPageSetupDialogImpl<CPageSetupDialog>(dwFlags, hWndParent)
2800         { }
2801
2802         // override PaintHookProc and references to handlers
2803         static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM)
2804         {
2805                 return 0;
2806         }
2807 };
2808
2809 #endif // _WIN32_WCE
2810
2811
2812 ///////////////////////////////////////////////////////////////////////////////
2813 // CFindReplaceDialogImpl - Find/FindReplace modeless dialogs
2814
2815 #ifndef _WIN32_WCE
2816
2817 template <class T>
2818 class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase
2819 {
2820 public:
2821         enum { _cchFindReplaceBuffer = 128 };
2822
2823         FINDREPLACE m_fr;
2824         TCHAR m_szFindWhat[_cchFindReplaceBuffer];
2825         TCHAR m_szReplaceWith[_cchFindReplaceBuffer];
2826
2827 // Constructors
2828         CFindReplaceDialogImpl()
2829         {
2830                 memset(&m_fr, 0, sizeof(m_fr));
2831                 m_szFindWhat[0] = _T('\0');
2832                 m_szReplaceWith[0] = _T('\0');
2833
2834                 m_fr.lStructSize = sizeof(m_fr);
2835                 m_fr.Flags = FR_ENABLEHOOK;
2836                 m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc;
2837                 m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat;
2838                 m_fr.wFindWhatLen = _cchFindReplaceBuffer;
2839                 m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith;
2840                 m_fr.wReplaceWithLen = _cchFindReplaceBuffer;
2841         }
2842
2843         // Note: You must allocate the object on the heap.
2844         //       If you do not, you must override OnFinalMessage()
2845         virtual void OnFinalMessage(HWND /*hWnd*/)
2846         {
2847                 delete this;
2848         }
2849
2850         HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace
2851                         LPCTSTR lpszFindWhat,
2852                         LPCTSTR lpszReplaceWith = NULL,
2853                         DWORD dwFlags = FR_DOWN,
2854                         HWND hWndParent = NULL)
2855         {
2856                 ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0);
2857                 ATLASSERT(m_fr.lpfnHook != NULL);
2858
2859                 m_fr.Flags |= dwFlags;
2860
2861                 if(hWndParent == NULL)
2862                         m_fr.hwndOwner = ::GetActiveWindow();
2863                 else
2864                         m_fr.hwndOwner = hWndParent;
2865                 ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog
2866
2867                 if(lpszFindWhat != NULL)
2868                         SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE);
2869
2870                 if(lpszReplaceWith != NULL)
2871                         SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE);
2872
2873                 ATLASSERT(m_hWnd == NULL);
2874                 ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2875
2876                 HWND hWnd = NULL;
2877                 if(bFindDialogOnly)
2878                         hWnd = ::FindText(&m_fr);
2879                 else
2880                         hWnd = ::ReplaceText(&m_fr);
2881
2882                 ATLASSERT(m_hWnd == hWnd);
2883                 return hWnd;
2884         }
2885
2886         static const UINT GetFindReplaceMsg()
2887         {
2888                 static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
2889                 return nMsgFindReplace;
2890         }
2891         // call while handling FINDMSGSTRING registered message
2892         // to retreive the object
2893         static T* PASCAL GetNotifier(LPARAM lParam)
2894         {
2895                 ATLASSERT(lParam != NULL);
2896                 T* pDlg = (T*)(lParam - offsetof(T, m_fr));
2897                 return pDlg;
2898         }
2899
2900 // Operations
2901         // Helpers for parsing information after successful return
2902         LPCTSTR GetFindString() const    // get find string
2903         {
2904                 return (LPCTSTR)m_fr.lpstrFindWhat;
2905         }
2906
2907         LPCTSTR GetReplaceString() const // get replacement string
2908         {
2909                 return (LPCTSTR)m_fr.lpstrReplaceWith;
2910         }
2911
2912         BOOL SearchDown() const          // TRUE if search down, FALSE is up
2913         {
2914                 return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE;
2915         }
2916
2917         BOOL FindNext() const            // TRUE if command is find next
2918         {
2919                 return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE;
2920         }
2921
2922         BOOL MatchCase() const           // TRUE if matching case
2923         {
2924                 return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE;
2925         }
2926
2927         BOOL MatchWholeWord() const      // TRUE if matching whole words only
2928         {
2929                 return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE;
2930         }
2931
2932         BOOL ReplaceCurrent() const      // TRUE if replacing current string
2933         {
2934                 return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE;
2935         }
2936
2937         BOOL ReplaceAll() const          // TRUE if replacing all occurrences
2938         {
2939                 return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE;
2940         }
2941
2942         BOOL IsTerminating() const       // TRUE if terminating dialog
2943         {
2944                 return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ;
2945         }
2946 };
2947
2948 class CFindReplaceDialog : public CFindReplaceDialogImpl<CFindReplaceDialog>
2949 {
2950 public:
2951         DECLARE_EMPTY_MSG_MAP()
2952 };
2953
2954 #endif // !_WIN32_WCE
2955
2956
2957 #if (_ATL_VER >= 0x800)
2958 typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX;
2959 typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX;
2960 #else // (_ATL_VER >= 0x800)
2961 typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX;
2962 #pragma pack(push, 4)
2963 struct DLGITEMTEMPLATEEX
2964 {
2965         DWORD helpID;
2966         DWORD exStyle;
2967         DWORD style;
2968         short x;
2969         short y;
2970         short cx;
2971         short cy;
2972         WORD id;
2973 };
2974 #pragma pack(pop)
2975 #endif // (_ATL_VER >= 0x800)
2976
2977
2978 ///////////////////////////////////////////////////////////////////////////////
2979 // CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX
2980
2981 class CMemDlgTemplate
2982 {
2983 public:
2984         enum StdCtrlType
2985         {
2986                 CTRL_BUTTON    = 0x0080,
2987                 CTRL_EDIT      = 0x0081,
2988                 CTRL_STATIC    = 0x0082,
2989                 CTRL_LISTBOX   = 0x0083,
2990                 CTRL_SCROLLBAR = 0x0084,
2991                 CTRL_COMBOBOX  = 0x0085
2992         };
2993
2994         CMemDlgTemplate() : m_pData(NULL), m_pPtr(NULL), m_cAllocated(0)
2995         { }
2996
2997         ~CMemDlgTemplate()
2998         {
2999                 Reset();
3000         }
3001
3002         bool IsValid() const
3003         {
3004                 return (m_pData != NULL);
3005         }
3006
3007         bool IsTemplateEx() const
3008         {
3009                 return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF);
3010         }
3011
3012         LPDLGTEMPLATE GetTemplatePtr()
3013         {
3014                 return reinterpret_cast<LPDLGTEMPLATE>(m_pData);
3015         }
3016
3017         DLGTEMPLATEEX* GetTemplateExPtr()
3018         {
3019                 return reinterpret_cast<DLGTEMPLATEEX*>(m_pData);
3020         }
3021
3022         void Reset()
3023         {
3024                 if (IsValid())
3025                         ATLVERIFY(::GlobalFree(m_pData) == NULL);
3026
3027                 m_pData = NULL;
3028                 m_pPtr = NULL;
3029                 m_cAllocated = 0;
3030         }
3031
3032         void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0, 
3033                     LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,
3034                                 ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)
3035         {
3036                 // Should have DS_SETFONT style to set the dialog font name and size
3037                 if (lpstrFontName != NULL)
3038                 {
3039                         dwStyle |= DS_SETFONT;
3040                 }
3041                 else
3042                 {
3043                         dwStyle &= ~DS_SETFONT;
3044                 }
3045
3046                 if (bDlgEx)
3047                 {
3048                         DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight};
3049                         AddData(&dlg, sizeof(dlg));
3050                 }
3051                 else
3052                 {
3053                         DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight};
3054                         AddData(&dlg, sizeof(dlg));
3055                 }
3056
3057 #ifndef _WIN32_WCE
3058                 if (Menu.m_lpstr == NULL)
3059                 {
3060                         WORD menuData = 0;
3061                         AddData(&menuData, sizeof(WORD));
3062                 }
3063                 else if (IS_INTRESOURCE(Menu.m_lpstr))
3064                 {
3065                         WORD menuData[] = {0xFFFF, (WORD)Menu.m_lpstr};
3066                         AddData(menuData, sizeof(menuData));
3067                 }
3068                 else
3069                 {
3070                         AddString(Menu.m_lpstr);
3071                 }
3072 #else // _WIN32_WCE
3073                 // Windows CE doesn't support the addition of menus to a dialog box
3074                 ATLASSERT(Menu.m_lpstr == NULL);
3075                 Menu.m_lpstr;   // avoid level 4 warning
3076                 WORD menuData = 0;
3077                 AddData(&menuData, sizeof(WORD));
3078 #endif // _WIN32_WCE
3079
3080                 if (ClassName.m_lpstr == NULL)
3081                 {
3082                         WORD classData = 0;
3083                         AddData(&classData, sizeof(WORD));
3084                 }
3085                 else if (IS_INTRESOURCE(ClassName.m_lpstr))
3086                 {
3087                         WORD classData[] = {0xFFFF, (WORD)ClassName.m_lpstr};
3088                         AddData(classData, sizeof(classData));
3089                 }
3090                 else
3091                 {
3092                         AddString(ClassName.m_lpstr);
3093                 }
3094
3095                 // Set dialog caption
3096                 AddString(lpszCaption);
3097
3098                 if (lpstrFontName != NULL)
3099                 {
3100                         AddData(&wFontSize, sizeof(wFontSize));
3101
3102                         if (bDlgEx)
3103                         {
3104                                 AddData(&wWeight, sizeof(wWeight));
3105                                 AddData(&bItalic, sizeof(bItalic));
3106                                 AddData(&bCharset, sizeof(bCharset));
3107                         }
3108
3109                         AddString(lpstrFontName);
3110                 }
3111         }
3112
3113         void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle,
3114                         ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
3115         {
3116                 ATLASSERT(IsValid());
3117
3118                 // DWORD align data
3119                 m_pPtr = (LPBYTE)(DWORD_PTR)((DWORD)(DWORD_PTR)(m_pPtr + 3) & (~3));
3120
3121                 if (IsTemplateEx())
3122                 {
3123                         DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData;
3124                         dlg->cDlgItems++;
3125
3126                         DLGITEMTEMPLATEEX item = {dwHelpID, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId};
3127                         AddData(&item, sizeof(item));
3128                 }
3129                 else
3130                 {
3131                         LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData;
3132                         dlg->cdit++;
3133
3134                         DLGITEMTEMPLATE item = {ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId};
3135                         AddData(&item, sizeof(item));
3136                 }
3137
3138                 ATLASSERT(ClassName.m_lpstr != NULL);
3139                 if (IS_INTRESOURCE(ClassName.m_lpstr))
3140                 {
3141                         WORD wData[] = {0xFFFF, (WORD)ClassName.m_lpstr};
3142                         AddData(wData, sizeof(wData));
3143                 }
3144                 else
3145                 {
3146                         AddString(ClassName.m_lpstr);
3147                 }
3148
3149                 if (Text.m_lpstr == NULL)
3150                 {
3151                         WORD classData = 0;
3152                         AddData(&classData, sizeof(WORD));
3153                 }
3154                 else if (IS_INTRESOURCE(Text.m_lpstr))
3155                 {
3156                         WORD wData[] = {0xFFFF, (WORD)Text.m_lpstr};
3157                         AddData(wData, sizeof(wData));
3158                 }
3159                 else
3160                 {
3161                         AddString(Text.m_lpstr);
3162                 }
3163
3164                 AddData(&nCreationData, sizeof(nCreationData));
3165
3166                 if ((nCreationData != 0))
3167                 {
3168                         ATLASSERT(pCreationData != NULL);
3169                         AddData(pCreationData, nCreationData * sizeof(WORD));
3170                 }
3171         }
3172
3173         void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight,
3174                            DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
3175         {
3176                 AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID);
3177         }
3178
3179 protected:
3180         void AddData(LPCVOID pData, size_t nData)
3181         {
3182                 ATLASSERT(pData != NULL);
3183
3184                 const size_t ALLOCATION_INCREMENT = 1024;
3185
3186                 if (m_pData == NULL)
3187                 {
3188                         m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
3189                         m_pPtr = m_pData = static_cast<LPBYTE>(::GlobalAlloc(GPTR, m_cAllocated));
3190                         ATLASSERT(m_pData != NULL);
3191                 }
3192                 else if (((m_pPtr - m_pData) + nData) > m_cAllocated)
3193                 {
3194                         size_t ptrPos = (m_pPtr - m_pData);
3195                         m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
3196                         m_pData = static_cast<LPBYTE>(::GlobalReAlloc(m_pData, m_cAllocated, 0));
3197                         ATLASSERT(m_pData != NULL);
3198                         m_pPtr = m_pData + ptrPos;
3199                 }
3200
3201                 SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData);
3202
3203                 m_pPtr += nData;
3204         }
3205
3206         void AddString(LPCTSTR lpszStr)
3207         {
3208                 if (lpszStr == NULL)
3209                 {
3210                         WCHAR szEmpty = 0;
3211                         AddData(&szEmpty, sizeof(szEmpty));
3212                 }
3213                 else
3214                 {
3215                         USES_CONVERSION;
3216                         LPCWSTR lpstr = T2CW(lpszStr);
3217                         int nSize = lstrlenW(lpstr) + 1;
3218                         AddData(lpstr, nSize * sizeof(WCHAR));
3219                 }
3220         }
3221
3222         LPBYTE m_pData;
3223         LPBYTE m_pPtr;
3224         SIZE_T m_cAllocated;
3225 };
3226
3227
3228 ///////////////////////////////////////////////////////////////////////////////
3229 // Dialog and control macros for indirect dialogs
3230
3231 // for DLGTEMPLATE
3232 #define BEGIN_DIALOG(x, y, width, height) \
3233         void DoInitTemplate() \
3234         { \
3235                 bool bExTemplate = false; \
3236                 short nX = x, nY = y, nWidth = width, nHeight = height; \
3237                 LPCTSTR szCaption = NULL; \
3238                 DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
3239                 DWORD dwExStyle = 0; \
3240                 LPCTSTR szFontName = NULL; \
3241                 WORD wFontSize = 0; \
3242                 WORD wWeight = 0; \
3243                 BYTE bItalic = 0; \
3244                 BYTE bCharset = 0; \
3245                 DWORD dwHelpID = 0; \
3246                 ATL::_U_STRINGorID Menu = 0U; \
3247                 ATL::_U_STRINGorID ClassName = 0U;
3248
3249 // for DLGTEMPLATEEX
3250 #define BEGIN_DIALOG_EX(x, y, width, height, helpID) \
3251         void DoInitTemplate() \
3252         { \
3253                 bool bExTemplate = true; \
3254                 short nX = x, nY = y, nWidth = width, nHeight = height; \
3255                 LPCTSTR szCaption = NULL; \
3256                 DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
3257                 DWORD dwExStyle = 0; \
3258                 LPCTSTR szFontName = NULL; \
3259                 WORD wFontSize = 0; \
3260                 WORD wWeight = 0; \
3261                 BYTE bItalic = 0; \
3262                 BYTE bCharset = 0; \
3263                 DWORD dwHelpID = helpID; \
3264                 ATL::_U_STRINGorID Menu = 0U; \
3265                 ATL::_U_STRINGorID ClassName = 0U;
3266
3267 #define END_DIALOG() \
3268                 m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \
3269         };
3270
3271 #define DIALOG_CAPTION(caption) \
3272                 szCaption = caption;
3273 #define DIALOG_STYLE(style) \
3274                 dwStyle = style;
3275 #define DIALOG_EXSTYLE(exStyle) \
3276                 dwExStyle = exStyle;
3277 #define DIALOG_FONT(pointSize, typeFace) \
3278                 wFontSize = pointSize; \
3279                 szFontName = typeFace;
3280 #define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \
3281                 ATLASSERT(bExTemplate); \
3282                 wFontSize = pointsize; \
3283                 szFontName = typeface; \
3284                 wWeight = weight; \
3285                 bItalic = italic; \
3286                 bCharset = charset;
3287 #define DIALOG_MENU(menuName) \
3288                 Menu = menuName;
3289 #define DIALOG_CLASS(className) \
3290                 ClassName = className;
3291
3292 #define BEGIN_CONTROLS_MAP() \
3293         void DoInitControls() \
3294         {
3295
3296 #define END_CONTROLS_MAP() \
3297         };
3298
3299
3300 #define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \
3301         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0);
3302 #define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \
3303         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0);
3304 #define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \
3305         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0);
3306 #define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
3307         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3308 #define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
3309         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3310 #ifndef _WIN32_WCE
3311 #define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \
3312         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3313 #endif // !_WIN32_WCE
3314 #define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \
3315         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
3316 #define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \
3317         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
3318 #define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \
3319         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3320 #define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \
3321         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3322 #define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
3323         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3324 #define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
3325         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3326 #define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \
3327         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
3328 #define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \
3329         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
3330 #define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \
3331         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0);
3332 #define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \
3333         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0);
3334 #define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \
3335         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0);
3336 #define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \
3337         m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0);
3338 #define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \
3339         m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0);
3340
3341
3342 ///////////////////////////////////////////////////////////////////////////////
3343 // CIndirectDialogImpl - dialogs with template in memory
3344
3345 template <class T, class TDlgTemplate = CMemDlgTemplate, class TBase = ATL::CDialogImpl<T, ATL::CWindow> >
3346 class ATL_NO_VTABLE CIndirectDialogImpl : public TBase
3347 {
3348 public:
3349         enum { IDD = 0 };   // no dialog template resource
3350
3351         TDlgTemplate m_Template;
3352
3353         void CreateTemplate()
3354         {
3355                 T* pT = static_cast<T*>(this);
3356                 pT->DoInitTemplate();
3357                 pT->DoInitControls();
3358         }
3359
3360         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
3361         {
3362                 T* pT = static_cast<T*>(this);
3363                 ATLASSERT(pT->m_hWnd == NULL);
3364
3365                 if (!m_Template.IsValid())
3366                         CreateTemplate();
3367
3368 #if (_ATL_VER >= 0x0800)
3369                 // Allocate the thunk structure here, where we can fail gracefully.
3370                 BOOL result = m_thunk.Init(NULL, NULL);
3371                 if (result == FALSE)
3372                 {
3373                         SetLastError(ERROR_OUTOFMEMORY);
3374                         return -1;
3375                 }
3376 #endif // (_ATL_VER >= 0x0800)
3377
3378                 ModuleHelper::AddCreateWndData(&m_thunk.cd, pT);
3379
3380 #ifdef _DEBUG
3381                 m_bModal = true;
3382 #endif // _DEBUG
3383
3384                 return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
3385         }
3386
3387         HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
3388         {
3389                 T* pT = static_cast<T*>(this);
3390                 ATLASSERT(pT->m_hWnd == NULL);
3391
3392                 if (!m_Template.IsValid())
3393                         CreateTemplate();
3394
3395 #if (_ATL_VER >= 0x0800)
3396                 // Allocate the thunk structure here, where we can fail gracefully.
3397                 BOOL result = m_thunk.Init(NULL, NULL);
3398                 if (result == FALSE) 
3399                 {
3400                         SetLastError(ERROR_OUTOFMEMORY);
3401                         return NULL;
3402                 }
3403 #endif // (_ATL_VER >= 0x0800)
3404
3405                 ModuleHelper::AddCreateWndData(&m_thunk.cd, pT);
3406
3407 #ifdef _DEBUG
3408                 m_bModal = false;
3409 #endif // _DEBUG
3410
3411                 HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
3412                 ATLASSERT(m_hWnd == hWnd);
3413
3414                 return hWnd;
3415         }
3416
3417         // for CComControl
3418         HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)
3419         {
3420                 return Create(hWndParent, dwInitParam);
3421         }
3422
3423         void DoInitTemplate() 
3424         {
3425                 ATLASSERT(FALSE);   // MUST be defined in derived class
3426         }
3427
3428         void DoInitControls() 
3429         {
3430                 ATLASSERT(FALSE);   // MUST be defined in derived class
3431         }
3432 };
3433
3434 ///////////////////////////////////////////////////////////////////////////////
3435 // CPropertySheetWindow - client side for a property sheet
3436
3437 class CPropertySheetWindow : public ATL::CWindow
3438 {
3439 public:
3440 // Constructors
3441         CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
3442         { }
3443
3444         CPropertySheetWindow& operator =(HWND hWnd)
3445         {
3446                 m_hWnd = hWnd;
3447                 return *this;
3448         }
3449
3450 // Attributes
3451         int GetPageCount() const
3452         {
3453                 ATLASSERT(::IsWindow(m_hWnd));
3454                 HWND hWndTabCtrl = GetTabControl();
3455                 ATLASSERT(hWndTabCtrl != NULL);
3456                 return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);
3457         }
3458
3459         HWND GetActivePage() const
3460         {
3461                 ATLASSERT(::IsWindow(m_hWnd));
3462                 return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);
3463         }
3464
3465         int GetActiveIndex() const
3466         {
3467                 ATLASSERT(::IsWindow(m_hWnd));
3468                 HWND hWndTabCtrl = GetTabControl();
3469                 ATLASSERT(hWndTabCtrl != NULL);
3470                 return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);
3471         }
3472
3473         BOOL SetActivePage(int nPageIndex)
3474         {
3475                 ATLASSERT(::IsWindow(m_hWnd));
3476                 return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L);
3477         }
3478
3479         BOOL SetActivePage(HPROPSHEETPAGE hPage)
3480         {
3481                 ATLASSERT(::IsWindow(m_hWnd));
3482                 ATLASSERT(hPage != NULL);
3483                 return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage);
3484         }
3485
3486         BOOL SetActivePageByID(int nPageID)
3487         {
3488                 ATLASSERT(::IsWindow(m_hWnd));
3489                 return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID);
3490         }
3491
3492         void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
3493         {
3494                 ATLASSERT(::IsWindow(m_hWnd));
3495                 ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
3496                 ATLASSERT(lpszText != NULL);
3497                 ::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText);
3498         }
3499
3500         HWND GetTabControl() const
3501         {
3502                 ATLASSERT(::IsWindow(m_hWnd));
3503                 return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);
3504         }
3505
3506         void SetFinishText(LPCTSTR lpszText)
3507         {
3508                 ATLASSERT(::IsWindow(m_hWnd));
3509                 ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);
3510         }
3511
3512         void SetWizardButtons(DWORD dwFlags)
3513         {
3514                 ATLASSERT(::IsWindow(m_hWnd));
3515                 ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);
3516         }
3517
3518 // Operations
3519         BOOL AddPage(HPROPSHEETPAGE hPage)
3520         {
3521                 ATLASSERT(::IsWindow(m_hWnd));
3522                 ATLASSERT(hPage != NULL);
3523                 return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
3524         }
3525
3526         BOOL AddPage(LPCPROPSHEETPAGE pPage)
3527         {
3528                 ATLASSERT(::IsWindow(m_hWnd));
3529                 ATLASSERT(pPage != NULL);
3530                 HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3531                 if(hPage == NULL)
3532                         return FALSE;
3533                 return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
3534         }
3535
3536 #ifndef _WIN32_WCE
3537         BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage)
3538         {
3539                 ATLASSERT(::IsWindow(m_hWnd));
3540                 ATLASSERT(hPage != NULL);
3541                 return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
3542         }
3543
3544         BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage)
3545         {
3546                 ATLASSERT(::IsWindow(m_hWnd));
3547                 ATLASSERT(pPage != NULL);
3548                 HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3549                 if(hPage == NULL)
3550                         return FALSE;
3551                 return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
3552         }
3553
3554         BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage)
3555         {
3556                 ATLASSERT(::IsWindow(m_hWnd));
3557                 ATLASSERT(hPage != NULL);
3558                 return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
3559         }
3560
3561         BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage)
3562         {
3563                 ATLASSERT(::IsWindow(m_hWnd));
3564                 ATLASSERT(pPage != NULL);
3565                 HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3566                 if(hPage == NULL)
3567                         return FALSE;
3568                 return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
3569         }
3570 #endif // !_WIN32_WCE
3571
3572         void RemovePage(int nPageIndex)
3573         {
3574                 ATLASSERT(::IsWindow(m_hWnd));
3575                 ::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L);
3576         }
3577
3578         void RemovePage(HPROPSHEETPAGE hPage)
3579         {
3580                 ATLASSERT(::IsWindow(m_hWnd));
3581                 ATLASSERT(hPage != NULL);
3582                 ::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage);
3583         }
3584
3585         BOOL PressButton(int nButton)
3586         {
3587                 ATLASSERT(::IsWindow(m_hWnd));
3588                 return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);
3589         }
3590
3591         BOOL Apply()
3592         {
3593                 ATLASSERT(::IsWindow(m_hWnd));
3594                 return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L);
3595         }
3596
3597         void CancelToClose()
3598         {
3599                 ATLASSERT(::IsWindow(m_hWnd));
3600                 ::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L);
3601         }
3602
3603         void SetModified(HWND hWndPage, BOOL bChanged = TRUE)
3604         {
3605                 ATLASSERT(::IsWindow(m_hWnd));
3606                 ATLASSERT(::IsWindow(hWndPage));
3607                 UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED;
3608                 ::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L);
3609         }
3610
3611         LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
3612         {
3613                 ATLASSERT(::IsWindow(m_hWnd));
3614                 return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam);
3615         }
3616
3617         void RebootSystem()
3618         {
3619                 ATLASSERT(::IsWindow(m_hWnd));
3620                 ::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L);
3621         }
3622
3623         void RestartWindows()
3624         {
3625                 ATLASSERT(::IsWindow(m_hWnd));
3626                 ::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L);
3627         }
3628
3629         BOOL IsDialogMessage(LPMSG lpMsg)
3630         {
3631                 ATLASSERT(::IsWindow(m_hWnd));
3632                 return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg);
3633         }
3634
3635 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
3636         int HwndToIndex(HWND hWnd) const
3637         {
3638                 ATLASSERT(::IsWindow(m_hWnd));
3639                 return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L);
3640         }
3641
3642         HWND IndexToHwnd(int nIndex) const
3643         {
3644                 ATLASSERT(::IsWindow(m_hWnd));
3645                 return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L);
3646         }
3647
3648         int PageToIndex(HPROPSHEETPAGE hPage) const
3649         {
3650                 ATLASSERT(::IsWindow(m_hWnd));
3651                 return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage);
3652         }
3653
3654         HPROPSHEETPAGE IndexToPage(int nIndex) const
3655         {
3656                 ATLASSERT(::IsWindow(m_hWnd));
3657                 return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L);
3658         }
3659
3660         int IdToIndex(int nID) const
3661         {
3662                 ATLASSERT(::IsWindow(m_hWnd));
3663                 return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID);
3664         }
3665
3666         int IndexToId(int nIndex) const
3667         {
3668                 ATLASSERT(::IsWindow(m_hWnd));
3669                 return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L);
3670         }
3671
3672         int GetResult() const
3673         {
3674                 ATLASSERT(::IsWindow(m_hWnd));
3675                 return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L);
3676         }
3677
3678         BOOL RecalcPageSizes()
3679         {
3680                 ATLASSERT(::IsWindow(m_hWnd));
3681                 return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L);
3682         }
3683
3684         void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle)
3685         {
3686                 ATLASSERT(::IsWindow(m_hWnd));
3687                 ::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle);
3688         }
3689
3690         void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle)
3691         {
3692                 ATLASSERT(::IsWindow(m_hWnd));
3693                 ::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle);
3694         }
3695 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
3696
3697 // Implementation - override to prevent usage
3698         HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
3699         {
3700                 ATLASSERT(FALSE);
3701                 return NULL;
3702         }
3703 };
3704
3705 ///////////////////////////////////////////////////////////////////////////////
3706 // CPropertySheetImpl - implements a property sheet
3707
3708 template <class T, class TBase = CPropertySheetWindow>
3709 class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase >
3710 {
3711 public:
3712         PROPSHEETHEADER m_psh;
3713         ATL::CSimpleArray<HPROPSHEETPAGE> m_arrPages;
3714
3715 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
3716   #ifndef PROPSHEET_LINK_SIZE
3717         #define PROPSHEET_LINK_SIZE 128
3718   #endif // PROPSHEET_LINK_SIZE
3719         TCHAR m_szLink[PROPSHEET_LINK_SIZE];
3720         static LPCTSTR m_pszTitle;
3721         static LPCTSTR m_pszLink;
3722 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 
3723
3724 // Construction/Destruction
3725         CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
3726         {
3727                 memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
3728                 m_psh.dwSize = sizeof(PROPSHEETHEADER);
3729                 m_psh.dwFlags = PSH_USECALLBACK;
3730                 m_psh.hInstance = ModuleHelper::GetResourceInstance();
3731                 m_psh.phpage = NULL;   // will be set later
3732                 m_psh.nPages = 0;      // will be set later
3733                 m_psh.pszCaption = title.m_lpstr;
3734                 m_psh.nStartPage = uStartPage;
3735                 m_psh.hwndParent = hWndParent;   // if NULL, will be set in DoModal/Create
3736                 m_psh.pfnCallback = T::PropSheetCallback;
3737
3738 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific 
3739                 m_psh.dwFlags |= PSH_MAXIMIZE;
3740                 m_szLink[0] = 0;
3741 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
3742         }
3743
3744         ~CPropertySheetImpl()
3745         {
3746                 if(m_arrPages.GetSize() > 0)   // sheet never created, destroy all pages
3747                 {
3748                         for(int i = 0; i < m_arrPages.GetSize(); i++)
3749                                 ::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]);
3750                 }
3751         }
3752
3753 // Callback function and overrideables
3754         static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
3755         {
3756                 lParam;   // avoid level 4 warning
3757                 int nRet = 0;
3758
3759                 if(uMsg == PSCB_INITIALIZED)
3760                 {
3761                         ATLASSERT(hWnd != NULL);
3762                         T* pT = (T*)ModuleHelper::ExtractCreateWndData();
3763                         // subclass the sheet window
3764                         pT->SubclassWindow(hWnd);
3765                         // remove page handles array
3766                         pT->_CleanUpPages();
3767
3768 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
3769                         m_pszTitle = pT->m_psh.pszCaption;
3770                         if(*pT->m_szLink != 0)
3771                                 m_pszLink = pT->m_szLink;
3772 #endif  // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
3773
3774                         pT->OnSheetInitialized();
3775                 }
3776 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg
3777                 else
3778                 {
3779                         switch(uMsg)
3780                         {
3781                         case PSCB_GETVERSION :
3782                                 nRet = COMCTL32_VERSION;
3783                                 break;
3784                         case PSCB_GETTITLE :
3785                                 if(m_pszTitle != NULL)
3786                                 {
3787                                         lstrcpy((LPTSTR)lParam, m_pszTitle);
3788                                         m_pszTitle = NULL;
3789                                 }
3790                                 break;
3791                         case PSCB_GETLINKTEXT:
3792                                 if(m_pszLink != NULL)
3793                                 {
3794                                         lstrcpy((LPTSTR)lParam, m_pszLink);
3795                                         m_pszLink = NULL;
3796                                 }
3797                                 break;
3798                         default:
3799                                 break;
3800                         }
3801                 }
3802 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 
3803
3804                 return nRet;
3805         }
3806
3807         void OnSheetInitialized()
3808         {
3809         }
3810
3811 // Create method
3812         HWND Create(HWND hWndParent = NULL)
3813         {
3814                 ATLASSERT(m_hWnd == NULL);
3815
3816                 m_psh.dwFlags |= PSH_MODELESS;
3817                 if(m_psh.hwndParent == NULL)
3818                         m_psh.hwndParent = hWndParent;
3819                 m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
3820                 m_psh.nPages = m_arrPages.GetSize();
3821
3822                 T* pT = static_cast<T*>(this);
3823                 ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
3824
3825                 HWND hWnd = (HWND)::PropertySheet(&m_psh);
3826                 _CleanUpPages();   // ensure clean-up, required if call failed
3827
3828                 ATLASSERT(m_hWnd == hWnd);
3829
3830                 return hWnd;
3831         }
3832
3833         INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
3834         {
3835                 ATLASSERT(m_hWnd == NULL);
3836
3837                 m_psh.dwFlags &= ~PSH_MODELESS;
3838                 if(m_psh.hwndParent == NULL)
3839                         m_psh.hwndParent = hWndParent;
3840                 m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
3841                 m_psh.nPages = m_arrPages.GetSize();
3842
3843                 T* pT = static_cast<T*>(this);
3844                 ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
3845
3846                 INT_PTR nRet = ::PropertySheet(&m_psh);
3847                 _CleanUpPages();   // ensure clean-up, required if call failed
3848
3849                 return nRet;
3850         }
3851
3852         // implementation helper - clean up pages array
3853         void _CleanUpPages()
3854         {
3855                 m_psh.nPages = 0;
3856                 m_psh.phpage = NULL;
3857                 m_arrPages.RemoveAll();
3858         }
3859
3860 // Attributes (extended overrides of client class methods)
3861 // These now can be called before the sheet is created
3862 // Note: Calling these after the sheet is created gives unpredictable results
3863         int GetPageCount() const
3864         {
3865                 if(m_hWnd == NULL)   // not created yet
3866                         return m_arrPages.GetSize();
3867                 return TBase::GetPageCount();
3868         }
3869
3870         int GetActiveIndex() const
3871         {
3872                 if(m_hWnd == NULL)   // not created yet
3873                         return m_psh.nStartPage;
3874                 return TBase::GetActiveIndex();
3875         }
3876
3877         HPROPSHEETPAGE GetPage(int nPageIndex) const
3878         {
3879                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
3880                 return (HPROPSHEETPAGE)m_arrPages[nPageIndex];
3881         }
3882
3883         int GetPageIndex(HPROPSHEETPAGE hPage) const
3884         {
3885                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
3886                 return m_arrPages.Find((HPROPSHEETPAGE&)hPage);
3887         }
3888
3889         BOOL SetActivePage(int nPageIndex)
3890         {
3891                 if(m_hWnd == NULL)   // not created yet
3892                 {
3893                         ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize());
3894                         m_psh.nStartPage = nPageIndex;
3895                         return TRUE;
3896                 }
3897                 return TBase::SetActivePage(nPageIndex);
3898         }
3899
3900         BOOL SetActivePage(HPROPSHEETPAGE hPage)
3901         {
3902                 ATLASSERT(hPage != NULL);
3903                 if (m_hWnd == NULL)   // not created yet
3904                 {
3905                         int nPageIndex = GetPageIndex(hPage);
3906                         if(nPageIndex == -1)
3907                                 return FALSE;
3908
3909                         return SetActivePage(nPageIndex);
3910                 }
3911                 return TBase::SetActivePage(hPage);
3912
3913         }
3914
3915         void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
3916         {
3917                 ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0);   // only PSH_PROPTITLE is valid
3918                 ATLASSERT(lpszText != NULL);
3919
3920                 if(m_hWnd == NULL)
3921                 {
3922                         // set internal state
3923                         m_psh.pszCaption = lpszText;   // must exist until sheet is created
3924                         m_psh.dwFlags &= ~PSH_PROPTITLE;
3925                         m_psh.dwFlags |= nStyle;
3926                 }
3927                 else
3928                 {
3929                         // set external state
3930                         TBase::SetTitle(lpszText, nStyle);
3931                 }
3932         }
3933
3934 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field 
3935         void SetLinkText(LPCTSTR lpszText)
3936         {
3937                 ATLASSERT(lpszText != NULL);
3938                 ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE);
3939                 lstrcpy(m_szLink, lpszText);
3940         }
3941 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 
3942
3943         void SetWizardMode()
3944         {
3945                 m_psh.dwFlags |= PSH_WIZARD;
3946         }
3947
3948         void EnableHelp()
3949         {
3950                 m_psh.dwFlags |= PSH_HASHELP;
3951         }
3952
3953 // Operations
3954         BOOL AddPage(HPROPSHEETPAGE hPage)
3955         {
3956                 ATLASSERT(hPage != NULL);
3957                 BOOL bRet = FALSE;
3958                 if(m_hWnd != NULL)
3959                         bRet = TBase::AddPage(hPage);
3960                 else    // sheet not created yet, use internal data
3961                         bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage);
3962                 return bRet;
3963         }
3964
3965         BOOL AddPage(LPCPROPSHEETPAGE pPage)
3966         {
3967                 ATLASSERT(pPage != NULL);
3968                 HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3969                 if(hPage == NULL)
3970                         return FALSE;
3971                 BOOL bRet = AddPage(hPage);
3972                 if(!bRet)
3973                         ::DestroyPropertySheetPage(hPage);
3974                 return bRet;
3975         }
3976
3977         BOOL RemovePage(HPROPSHEETPAGE hPage)
3978         {
3979                 ATLASSERT(hPage != NULL);
3980                 if (m_hWnd == NULL)   // not created yet
3981                 {
3982                         int nPage = GetPageIndex(hPage);
3983                         if(nPage == -1)
3984                                 return FALSE;
3985                         return RemovePage(nPage);
3986                 }
3987                 TBase::RemovePage(hPage);
3988                 return TRUE;
3989
3990         }
3991
3992         BOOL RemovePage(int nPageIndex)
3993         {
3994                 BOOL bRet = TRUE;
3995                 if(m_hWnd != NULL)
3996                         TBase::RemovePage(nPageIndex);
3997                 else    // sheet not created yet, use internal data
3998                         bRet = m_arrPages.RemoveAt(nPageIndex);
3999                 return bRet;
4000         }
4001
4002 #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
4003         void SetHeader(LPCTSTR szbmHeader)
4004         {
4005                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4006
4007                 m_psh.dwFlags &= ~PSH_WIZARD;
4008                 m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97);
4009                 m_psh.pszbmHeader = szbmHeader;
4010         }
4011
4012         void SetHeader(HBITMAP hbmHeader)
4013         {
4014                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4015
4016                 m_psh.dwFlags &= ~PSH_WIZARD;
4017                 m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97);
4018                 m_psh.hbmHeader = hbmHeader;
4019         }
4020
4021         void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL)
4022         {
4023                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4024
4025                 m_psh.dwFlags &= ~PSH_WIZARD;
4026                 m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97;
4027                 m_psh.pszbmWatermark = szbmWatermark;
4028
4029                 if (hplWatermark != NULL)
4030                 {
4031                         m_psh.dwFlags |= PSH_USEHPLWATERMARK;
4032                         m_psh.hplWatermark = hplWatermark;
4033                 }
4034         }
4035
4036         void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL)
4037         {
4038                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4039
4040                 m_psh.dwFlags &= ~PSH_WIZARD;
4041                 m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97);
4042                 m_psh.hbmWatermark = hbmWatermark;
4043
4044                 if (hplWatermark != NULL)
4045                 {
4046                         m_psh.dwFlags |= PSH_USEHPLWATERMARK;
4047                         m_psh.hplWatermark = hplWatermark;
4048                 }
4049         }
4050
4051         void StretchWatermark(bool bStretchWatermark)
4052         {
4053                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4054                 if (bStretchWatermark)
4055                         m_psh.dwFlags |= PSH_STRETCHWATERMARK;
4056                 else
4057                         m_psh.dwFlags &= ~PSH_STRETCHWATERMARK;
4058         }
4059 #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
4060
4061 // Message map and handlers
4062         BEGIN_MSG_MAP(CPropertySheetImpl)
4063                 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
4064                 MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
4065         END_MSG_MAP()
4066
4067         LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
4068         {
4069                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
4070                 if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) &&
4071                    ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))
4072                         DestroyWindow();
4073                 return lRet;
4074         }
4075
4076         LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
4077         {
4078                 if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE))
4079                         SendMessage(WM_CLOSE);
4080                 else
4081                         bHandled = FALSE;
4082                 return 0;
4083         }
4084 };
4085
4086 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers
4087 template < class T, class TBase >
4088 LPCWSTR CPropertySheetImpl<T,TBase>::m_pszTitle = NULL;
4089 template < class T, class TBase>
4090 LPCWSTR CPropertySheetImpl<T,TBase>::m_pszLink = NULL;
4091 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
4092
4093 // for non-customized sheets
4094 class CPropertySheet : public CPropertySheetImpl<CPropertySheet>
4095 {
4096 public:
4097         CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
4098                 : CPropertySheetImpl<CPropertySheet>(title, uStartPage, hWndParent)
4099         { }
4100 };
4101
4102
4103 ///////////////////////////////////////////////////////////////////////////////
4104 // CPropertyPageWindow - client side for a property page
4105
4106 class CPropertyPageWindow : public ATL::CWindow
4107 {
4108 public:
4109 // Constructors
4110         CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
4111         { }
4112
4113         CPropertyPageWindow& operator =(HWND hWnd)
4114         {
4115                 m_hWnd = hWnd;
4116                 return *this;
4117         }
4118
4119 // Attributes
4120         CPropertySheetWindow GetPropertySheet() const
4121         {
4122                 ATLASSERT(::IsWindow(m_hWnd));
4123                 return CPropertySheetWindow(GetParent());
4124         }
4125
4126 // Operations
4127         BOOL Apply()
4128         {
4129                 ATLASSERT(::IsWindow(m_hWnd));
4130                 ATLASSERT(GetParent() != NULL);
4131                 return GetPropertySheet().Apply();
4132         }
4133
4134         void CancelToClose()
4135         {
4136                 ATLASSERT(::IsWindow(m_hWnd));
4137                 ATLASSERT(GetParent() != NULL);
4138                 GetPropertySheet().CancelToClose();
4139         }
4140
4141         void SetModified(BOOL bChanged = TRUE)
4142         {
4143                 ATLASSERT(::IsWindow(m_hWnd));
4144                 ATLASSERT(GetParent() != NULL);
4145                 GetPropertySheet().SetModified(m_hWnd, bChanged);
4146         }
4147
4148         LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
4149         {
4150                 ATLASSERT(::IsWindow(m_hWnd));
4151                 ATLASSERT(GetParent() != NULL);
4152                 return GetPropertySheet().QuerySiblings(wParam, lParam);
4153         }
4154
4155         void RebootSystem()
4156         {
4157                 ATLASSERT(::IsWindow(m_hWnd));
4158                 ATLASSERT(GetParent() != NULL);
4159                 GetPropertySheet().RebootSystem();
4160         }
4161
4162         void RestartWindows()
4163         {
4164                 ATLASSERT(::IsWindow(m_hWnd));
4165                 ATLASSERT(GetParent() != NULL);
4166                 GetPropertySheet().RestartWindows();
4167         }
4168
4169         void SetWizardButtons(DWORD dwFlags)
4170         {
4171                 ATLASSERT(::IsWindow(m_hWnd));
4172                 ATLASSERT(GetParent() != NULL);
4173                 GetPropertySheet().SetWizardButtons(dwFlags);
4174         }
4175
4176 // Implementation - overrides to prevent usage
4177         HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
4178         {
4179                 ATLASSERT(FALSE);
4180                 return NULL;
4181         }
4182 };
4183
4184 ///////////////////////////////////////////////////////////////////////////////
4185 // CPropertyPageImpl - implements a property page
4186
4187 template <class T, class TBase = CPropertyPageWindow>
4188 class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase >
4189 {
4190 public:
4191         PROPSHEETPAGE m_psp;
4192
4193         operator PROPSHEETPAGE*() { return &m_psp; }
4194
4195 // Construction
4196         CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
4197         {
4198                 // initialize PROPSHEETPAGE struct
4199                 memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
4200                 m_psp.dwSize = sizeof(PROPSHEETPAGE);
4201                 m_psp.dwFlags = PSP_USECALLBACK;
4202                 m_psp.hInstance = ModuleHelper::GetResourceInstance();
4203                 T* pT = static_cast<T*>(this);
4204                 m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD);
4205                 m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;
4206                 m_psp.pfnCallback = T::PropPageCallback;
4207                 m_psp.lParam = (LPARAM)pT;
4208
4209                 if(title.m_lpstr != NULL)
4210                         SetTitle(title);
4211         }
4212
4213 // Callback function and overrideables
4214         static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
4215         {
4216                 hWnd;   // avoid level 4 warning
4217                 ATLASSERT(hWnd == NULL);
4218                 T* pT = (T*)ppsp->lParam;
4219                 UINT uRet = 0;
4220
4221                 switch(uMsg)
4222                 {
4223                 case PSPCB_CREATE:
4224                         {
4225                                 ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT;
4226                                 ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage);
4227                                 uRet = pT->OnPageCreate() ? 1 : 0;
4228                         }
4229                         break;
4230 #if (_WIN32_IE >= 0x0500)
4231                 case PSPCB_ADDREF:
4232                         pT->OnPageAddRef();
4233                         break;
4234 #endif // (_WIN32_IE >= 0x0500)
4235                 case PSPCB_RELEASE:
4236                         pT->OnPageRelease();
4237                         break;
4238                 default:
4239                         break;
4240                 }
4241
4242                 return uRet;
4243         }
4244
4245         bool OnPageCreate()
4246         {
4247                 return true;   // true - allow page to be created, false - prevent creation
4248         }
4249
4250 #if (_WIN32_IE >= 0x0500)
4251         void OnPageAddRef()
4252         {
4253         }
4254 #endif // (_WIN32_IE >= 0x0500)
4255
4256         void OnPageRelease()
4257         {
4258         }
4259
4260 // Create method
4261         HPROPSHEETPAGE Create()
4262         {
4263                 return ::CreatePropertySheetPage(&m_psp);
4264         }
4265
4266 // Attributes
4267         void SetTitle(ATL::_U_STRINGorID title)
4268         {
4269                 m_psp.pszTitle = title.m_lpstr;
4270                 m_psp.dwFlags |= PSP_USETITLE;
4271         }
4272
4273 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
4274         void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)
4275         {
4276                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4277                 m_psp.dwFlags |= PSP_USEHEADERTITLE;
4278                 m_psp.pszHeaderTitle = lpstrHeaderTitle;
4279         }
4280
4281         void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)
4282         {
4283                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4284                 m_psp.dwFlags |= PSP_USEHEADERSUBTITLE;
4285                 m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle;
4286         }
4287 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
4288
4289 // Operations
4290         void EnableHelp()
4291         {
4292                 m_psp.dwFlags |= PSP_HASHELP;
4293         }
4294
4295 // Message map and handlers
4296         BEGIN_MSG_MAP(CPropertyPageImpl)
4297                 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
4298         END_MSG_MAP()
4299
4300         // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
4301         // handlers that return direct values without any restrictions
4302         LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
4303         {
4304 #ifndef _WIN32_WCE
4305                 // This notification is sometimes received on Windows CE after the window is already destroyed
4306                 ATLASSERT(::IsWindow(m_hWnd));
4307 #endif
4308                 NMHDR* pNMHDR = (NMHDR*)lParam;
4309
4310                 // don't handle messages not from the page/sheet itself
4311                 if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
4312                 {
4313                         bHandled = FALSE;
4314                         return 1;
4315                 }
4316 #ifdef _WIN32_WCE
4317                 ATLASSERT(::IsWindow(m_hWnd));
4318 #endif
4319
4320                 T* pT = static_cast<T*>(this);
4321                 LRESULT lResult = 0;
4322                 switch(pNMHDR->code)
4323                 {
4324 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
4325                 case PSN_SETACTIVE:
4326                         lResult = pT->OnSetActive();
4327                         break;
4328                 case PSN_KILLACTIVE:
4329                         lResult = pT->OnKillActive();
4330                         break;
4331                 case PSN_APPLY:
4332                         lResult = pT->OnApply();
4333                         break;
4334                 case PSN_RESET:
4335                         pT->OnReset();
4336                         break;
4337                 case PSN_QUERYCANCEL:
4338                         lResult = pT->OnQueryCancel();
4339                         break;
4340                 case PSN_WIZNEXT:
4341                         lResult = pT->OnWizardNext();
4342                         break;
4343                 case PSN_WIZBACK:
4344                         lResult = pT->OnWizardBack();
4345                         break;
4346                 case PSN_WIZFINISH:
4347                         lResult = pT->OnWizardFinish();
4348                         break;
4349                 case PSN_HELP:
4350                         pT->OnHelp();
4351                         break;
4352 #ifndef _WIN32_WCE
4353 #if (_WIN32_IE >= 0x0400)
4354                 case PSN_GETOBJECT:
4355                         if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
4356                                 bHandled = FALSE;
4357                         break;
4358 #endif // (_WIN32_IE >= 0x0400)
4359 #if (_WIN32_IE >= 0x0500)
4360                 case PSN_TRANSLATEACCELERATOR:
4361                         {
4362                                 LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4363                                 lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam);
4364                         }
4365                         break;
4366                 case PSN_QUERYINITIALFOCUS:
4367                         {
4368                                 LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4369                                 lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
4370                         }
4371                         break;
4372 #endif // (_WIN32_IE >= 0x0500)
4373 #endif // !_WIN32_WCE
4374
4375 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4376                 case PSN_SETACTIVE:
4377                         lResult = pT->OnSetActive() ? 0 : -1;
4378                         break;
4379                 case PSN_KILLACTIVE:
4380                         lResult = !pT->OnKillActive();
4381                         break;
4382                 case PSN_APPLY:
4383                         lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
4384                         break;
4385                 case PSN_RESET:
4386                         pT->OnReset();
4387                         break;
4388                 case PSN_QUERYCANCEL:
4389                         lResult = !pT->OnQueryCancel();
4390                         break;
4391                 case PSN_WIZNEXT:
4392                         lResult = pT->OnWizardNext();
4393                         break;
4394                 case PSN_WIZBACK:
4395                         lResult = pT->OnWizardBack();
4396                         break;
4397                 case PSN_WIZFINISH:
4398                         lResult = !pT->OnWizardFinish();
4399                         break;
4400                 case PSN_HELP:
4401                         pT->OnHelp();
4402                         break;
4403 #ifndef _WIN32_WCE
4404 #if (_WIN32_IE >= 0x0400)
4405                 case PSN_GETOBJECT:
4406                         if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
4407                                 bHandled = FALSE;
4408                         break;
4409 #endif // (_WIN32_IE >= 0x0400)
4410 #if (_WIN32_IE >= 0x0500)
4411                 case PSN_TRANSLATEACCELERATOR:
4412                         {
4413                                 LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4414                                 lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
4415                         }
4416                         break;
4417                 case PSN_QUERYINITIALFOCUS:
4418                         {
4419                                 LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4420                                 lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
4421                         }
4422                         break;
4423 #endif // (_WIN32_IE >= 0x0500)
4424 #endif // !_WIN32_WCE
4425
4426 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4427                 default:
4428                         bHandled = FALSE;   // not handled
4429                 }
4430
4431                 return lResult;
4432         }
4433
4434 // Overridables
4435         // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
4436         // handlers that return direct values without any restrictions
4437 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
4438         int OnSetActive()
4439         {
4440                 // 0 = allow activate
4441                 // -1 = go back that was active
4442                 // page ID = jump to page
4443                 return 0;
4444         }
4445
4446         BOOL OnKillActive()
4447         {
4448                 // FALSE = allow deactivate
4449                 // TRUE = prevent deactivation
4450                 return FALSE;
4451         }
4452
4453         int OnApply()
4454         {
4455                 // PSNRET_NOERROR = apply OK
4456                 // PSNRET_INVALID = apply not OK, return to this page
4457                 // PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus
4458                 return PSNRET_NOERROR;
4459         }
4460
4461         void OnReset()
4462         {
4463         }
4464
4465         BOOL OnQueryCancel()
4466         {
4467                 // FALSE = allow cancel
4468                 // TRUE = prevent cancel
4469                 return FALSE;
4470         }
4471
4472         int OnWizardBack()
4473         {
4474                 // 0  = goto previous page
4475                 // -1 = prevent page change
4476                 // >0 = jump to page by dlg ID
4477                 return 0;
4478         }
4479
4480         int OnWizardNext()
4481         {
4482                 // 0  = goto next page
4483                 // -1 = prevent page change
4484                 // >0 = jump to page by dlg ID
4485                 return 0;
4486         }
4487
4488         INT_PTR OnWizardFinish()
4489         {
4490                 // FALSE = allow finish
4491                 // TRUE = prevent finish
4492                 // HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only)
4493                 return FALSE;
4494         }
4495
4496         void OnHelp()
4497         {
4498         }
4499
4500 #ifndef _WIN32_WCE
4501 #if (_WIN32_IE >= 0x0400)
4502         BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
4503         {
4504                 return FALSE;   // not processed
4505         }
4506 #endif // (_WIN32_IE >= 0x0400)
4507
4508 #if (_WIN32_IE >= 0x0500)
4509         int OnTranslateAccelerator(LPMSG /*lpMsg*/)
4510         {
4511                 // PSNRET_NOERROR - message not handled
4512                 // PSNRET_MESSAGEHANDLED - message handled
4513                 return PSNRET_NOERROR;
4514         }
4515
4516         HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
4517         {
4518                 // NULL = set focus to default control
4519                 // HWND = set focus to HWND
4520                 return NULL;
4521         }
4522 #endif // (_WIN32_IE >= 0x0500)
4523 #endif // !_WIN32_WCE
4524
4525 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4526         BOOL OnSetActive()
4527         {
4528                 return TRUE;
4529         }
4530
4531         BOOL OnKillActive()
4532         {
4533                 return TRUE;
4534         }
4535
4536         BOOL OnApply()
4537         {
4538                 return TRUE;
4539         }
4540
4541         void OnReset()
4542         {
4543         }
4544
4545         BOOL OnQueryCancel()
4546         {
4547                 return TRUE;    // ok to cancel
4548         }
4549
4550         int OnWizardBack()
4551         {
4552                 // 0  = goto previous page
4553                 // -1 = prevent page change
4554                 // >0 = jump to page by dlg ID
4555                 return 0;
4556         }
4557
4558         int OnWizardNext()
4559         {
4560                 // 0  = goto next page
4561                 // -1 = prevent page change
4562                 // >0 = jump to page by dlg ID
4563                 return 0;
4564         }
4565
4566         BOOL OnWizardFinish()
4567         {
4568                 return TRUE;
4569         }
4570
4571         void OnHelp()
4572         {
4573         }
4574
4575 #ifndef _WIN32_WCE
4576 #if (_WIN32_IE >= 0x0400)
4577         BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
4578         {
4579                 return FALSE;   // not processed
4580         }
4581 #endif // (_WIN32_IE >= 0x0400)
4582
4583 #if (_WIN32_IE >= 0x0500)
4584         BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/)
4585         {
4586                 return FALSE;   // not translated
4587         }
4588
4589         HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
4590         {
4591                 return NULL;   // default
4592         }
4593 #endif // (_WIN32_IE >= 0x0500)
4594 #endif // !_WIN32_WCE
4595
4596 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4597 };
4598
4599 // for non-customized pages
4600 template <WORD t_wDlgTemplateID>
4601 class CPropertyPage : public CPropertyPageImpl<CPropertyPage<t_wDlgTemplateID> >
4602 {
4603 public:
4604         enum { IDD = t_wDlgTemplateID };
4605
4606         CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<CPropertyPage>(title)
4607         { }
4608
4609         DECLARE_EMPTY_MSG_MAP()
4610 };
4611
4612 ///////////////////////////////////////////////////////////////////////////////
4613 // CAxPropertyPageImpl - property page that hosts ActiveX controls
4614
4615 #ifndef _ATL_NO_HOSTING
4616
4617 // Note: You must #include <atlhost.h> to use these classes
4618
4619 template <class T, class TBase = CPropertyPageWindow>
4620 class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase >
4621 {
4622 public:
4623 // Data members
4624         HGLOBAL m_hInitData;
4625         HGLOBAL m_hDlgRes;
4626         HGLOBAL m_hDlgResSplit;
4627
4628 // Constructor/destructor
4629         CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : 
4630                         CPropertyPageImpl< T, TBase >(title),
4631                         m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL)
4632         {
4633                 T* pT = static_cast<T*>(this);
4634                 pT;   // avoid level 4 warning
4635
4636                 // initialize ActiveX hosting and modify dialog template
4637                 ATL::AtlAxWinInit();
4638
4639                 HINSTANCE hInstance = ModuleHelper::GetResourceInstance();
4640                 LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD);
4641                 HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG);
4642                 if(hDlg != NULL)
4643                 {
4644                         HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT);
4645
4646                         BYTE* pInitData = NULL;
4647                         if(hDlgInit != NULL)
4648                         {
4649                                 m_hInitData = ::LoadResource(hInstance, hDlgInit);
4650                                 pInitData = (BYTE*)::LockResource(m_hInitData);
4651                         }
4652
4653                         m_hDlgRes = ::LoadResource(hInstance, hDlg);
4654                         DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes);
4655                         LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData);
4656                         if(lpDialogTemplate != pDlg)
4657                                 m_hDlgResSplit = GlobalHandle(lpDialogTemplate);
4658
4659                         // set up property page to use in-memory dialog template
4660                         if(lpDialogTemplate != NULL)
4661                         {
4662                                 m_psp.dwFlags |= PSP_DLGINDIRECT;
4663                                 m_psp.pResource = lpDialogTemplate;
4664                         }
4665                         else
4666                         {
4667                                 ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!"));
4668                         }
4669                 }
4670                 else
4671                 {
4672                         ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!"));
4673                 }
4674         }
4675
4676         ~CAxPropertyPageImpl()
4677         {
4678                 if(m_hInitData != NULL)
4679                 {
4680                         UnlockResource(m_hInitData);
4681                         FreeResource(m_hInitData);
4682                 }
4683                 if(m_hDlgRes != NULL)
4684                 {
4685                         UnlockResource(m_hDlgRes);
4686                         FreeResource(m_hDlgRes);
4687                 }
4688                 if(m_hDlgResSplit != NULL)
4689                 {
4690                         ::GlobalFree(m_hDlgResSplit);
4691                 }
4692         }
4693
4694 // Methods
4695         // call this one to handle keyboard message for ActiveX controls
4696         BOOL PreTranslateMessage(LPMSG pMsg)
4697         {
4698                 if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
4699                    (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
4700                         return FALSE;
4701                 // find a direct child of the dialog from the window that has focus
4702                 HWND hWndCtl = ::GetFocus();
4703                 if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd)
4704                 {
4705                         do
4706                         {
4707                                 hWndCtl = ::GetParent(hWndCtl);
4708                         }
4709                         while (::GetParent(hWndCtl) != m_hWnd);
4710                 }
4711                 // give controls a chance to translate this message
4712                 return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg);
4713         }
4714
4715 // Overridables
4716 #if (_WIN32_IE >= 0x0500)
4717         // new default implementation for ActiveX hosting pages
4718 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
4719         int OnTranslateAccelerator(LPMSG lpMsg)
4720         {
4721                 T* pT = static_cast<T*>(this);
4722                 return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
4723         }
4724 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4725         BOOL OnTranslateAccelerator(LPMSG lpMsg)
4726         {
4727                 T* pT = static_cast<T*>(this);
4728                 return pT->PreTranslateMessage(lpMsg);
4729         }
4730 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4731 #endif // (_WIN32_IE >= 0x0500)
4732
4733 // Support for new stuff in ATL7
4734 #if (_ATL_VER >= 0x0700)
4735         int GetIDD()
4736         {
4737                 return( static_cast<T*>(this)->IDD );
4738         }
4739
4740         virtual DLGPROC GetDialogProc()
4741         {
4742                 return DialogProc;
4743         }
4744
4745         static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4746         {
4747                 CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd;
4748                 if (uMsg == WM_INITDIALOG)
4749                 {
4750                         HRESULT hr;
4751                         if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD())))
4752                         {
4753                                 ATLASSERT(FALSE);
4754                                 return FALSE;
4755                         }
4756                 }
4757                 return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam);
4758         }
4759
4760 // ActiveX controls creation
4761         virtual HRESULT CreateActiveXControls(UINT nID)
4762         {
4763                 // Load dialog template and InitData
4764                 HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT);
4765                 BYTE* pInitData = NULL;
4766                 HGLOBAL hData = NULL;
4767                 HRESULT hr = S_OK;
4768                 if (hDlgInit != NULL)
4769                 {
4770                         hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit);
4771                         if (hData != NULL)
4772                                 pInitData = (BYTE*) ::LockResource(hData);
4773                 }
4774
4775                 HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG);
4776                 if (hDlg != NULL)
4777                 {
4778                         HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg);
4779                         DLGTEMPLATE* pDlg = NULL;
4780                         if (hResource != NULL)
4781                         {
4782                                 pDlg = (DLGTEMPLATE*) ::LockResource(hResource);
4783                                 if (pDlg != NULL)
4784                                 {
4785                                         // Get first control on the template
4786                                         BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg);
4787                                         WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg);
4788
4789                                         // Get first control on the dialog
4790                                         DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg);
4791                                         HWND hWndPrev = GetWindow(GW_CHILD);
4792
4793                                         // Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order)
4794                                         for (WORD nItem = 0; nItem < nItems; nItem++)
4795                                         {
4796                                                 DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id;
4797                                                 if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx))
4798                                                 {
4799                                                         BYTE* pData = NULL;
4800                                                         DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData);
4801                                                         ATL::CComPtr<IStream> spStream;
4802                                                         if (dwLen != 0)
4803                                                         {
4804                                                                 HGLOBAL h = GlobalAlloc(GHND, dwLen);
4805                                                                 if (h != NULL)
4806                                                                 {
4807                                                                         BYTE* pBytes = (BYTE*) GlobalLock(h);
4808                                                                         BYTE* pSource = pData; 
4809                                                                         SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen);
4810                                                                         GlobalUnlock(h);
4811                                                                         CreateStreamOnHGlobal(h, TRUE, &spStream);
4812                                                                 }
4813                                                                 else
4814                                                                 {
4815                                                                         hr = E_OUTOFMEMORY;
4816                                                                         break;
4817                                                                 }
4818                                                         }
4819
4820                                                         ATL::CComBSTR bstrLicKey;
4821                                                         hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str);
4822                                                         if (SUCCEEDED(hr))
4823                                                         {
4824                                                                 ATL::CAxWindow2 wnd;
4825                                                                 // Get control caption.
4826                                                                 LPWSTR pszClassName = 
4827                                                                         bDialogEx ? 
4828                                                                                 (LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) :
4829                                                                                 (LPWSTR)(pItem + 1);
4830                                                                 // Get control rect.
4831                                                                 RECT rect;
4832                                                                 rect.left = 
4833                                                                         bDialogEx ? 
4834                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : 
4835                                                                                 pItem->x;
4836                                                                 rect.top = 
4837                                                                         bDialogEx ? 
4838                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : 
4839                                                                                 pItem->y;
4840                                                                 rect.right = rect.left + 
4841                                                                         (bDialogEx ? 
4842                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : 
4843                                                                                 pItem->cx);
4844                                                                 rect.bottom = rect.top + 
4845                                                                         (bDialogEx ? 
4846                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : 
4847                                                                                 pItem->cy);
4848
4849                                                                 // Convert from dialog units to screen units
4850                                                                 MapDialogRect(&rect);
4851
4852                                                                 // Create AxWindow with a NULL caption.
4853                                                                 wnd.Create(m_hWnd, 
4854                                                                         &rect, 
4855                                                                         NULL, 
4856                                                                         (bDialogEx ? 
4857                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : 
4858                                                                                 pItem->style) | WS_TABSTOP, 
4859                                                                         bDialogEx ? 
4860                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : 
4861                                                                                 0,
4862                                                                         bDialogEx ? 
4863                                                                                 ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : 
4864                                                                                 pItem->id,
4865                                                                         NULL);
4866
4867                                                                 if (wnd != NULL)
4868                                                                 {
4869 #ifndef _WIN32_WCE
4870                                                                         // Set the Help ID
4871                                                                         if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0)
4872                                                                                 wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID);
4873 #endif // !_WIN32_WCE
4874                                                                         // Try to create the ActiveX control.
4875                                                                         hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey);
4876                                                                         if (FAILED(hr))
4877                                                                                 break;
4878                                                                         // Set the correct tab position.
4879                                                                         if (nItem == 0)
4880                                                                                 hWndPrev = HWND_TOP;
4881                                                                         wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
4882                                                                         hWndPrev = wnd;
4883                                                                 }
4884                                                                 else
4885                                                                 {
4886                                                                         hr = ATL::AtlHresultFromLastError();
4887                                                                 }
4888                                                         }
4889                                                 }
4890                                                 else
4891                                                 {
4892                                                         if (nItem != 0)
4893                                                                 hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);
4894                                                 }
4895                                                 pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx);
4896                                         }
4897                                 }
4898                                 else
4899                                         hr = ATL::AtlHresultFromLastError();
4900                         }
4901                         else
4902                                 hr = ATL::AtlHresultFromLastError();
4903                 }
4904                 return hr;
4905         }
4906
4907 // Event handling support
4908         HRESULT AdviseSinkMap(bool bAdvise)
4909         {
4910                 if(!bAdvise && m_hWnd == NULL)
4911                 {
4912                         // window is gone, controls are already unadvised
4913                         ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n"));
4914                         return S_OK;
4915                 }
4916                 HRESULT hRet = E_NOTIMPL;
4917                 __if_exists(T::_GetSinkMapFinder)
4918                 {
4919                         T* pT = static_cast<T*>(this);
4920                         hRet = AtlAdviseSinkMap(pT, bAdvise);
4921                 }
4922                 return hRet;
4923         }
4924
4925 // Message map and handlers
4926         typedef CPropertyPageImpl< T, TBase>   _baseClass;
4927         BEGIN_MSG_MAP(CAxPropertyPageImpl)
4928                 MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
4929                 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
4930                 CHAIN_MSG_MAP(_baseClass)
4931         END_MSG_MAP()
4932
4933         LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
4934         {
4935                 // initialize controls in dialog with DLGINIT resource section
4936                 ExecuteDlgInit(static_cast<T*>(this)->IDD);
4937                 AdviseSinkMap(true);
4938                 bHandled = FALSE;
4939                 return 1;
4940         }
4941
4942         LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
4943         {
4944                 AdviseSinkMap(false);
4945                 bHandled = FALSE;
4946                 return 1;
4947         }
4948 #endif // (_ATL_VER >= 0x0700)
4949 };
4950
4951 // for non-customized pages
4952 template <WORD t_wDlgTemplateID>
4953 class CAxPropertyPage : public CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >
4954 {
4955 public:
4956         enum { IDD = t_wDlgTemplateID };
4957
4958         CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl<CAxPropertyPage>(title)
4959         { }
4960
4961 #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
4962         // not empty so we handle accelerators/create controls
4963         BEGIN_MSG_MAP(CAxPropertyPage)
4964                 CHAIN_MSG_MAP(CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >)
4965         END_MSG_MAP()
4966 #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
4967         DECLARE_EMPTY_MSG_MAP()
4968 #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
4969 };
4970
4971 #endif // _ATL_NO_HOSTING
4972
4973
4974 ///////////////////////////////////////////////////////////////////////////////
4975 // Wizard97 Support
4976
4977 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
4978
4979 // Sample wizard dialog resources:
4980 //
4981 // IDD_WIZ97_INTERIOR_BLANK DIALOG  0, 0, 317, 143
4982 // STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
4983 // CAPTION "Wizard97 Property Page - Interior"
4984 // FONT 8, "MS Shell Dlg"
4985 // BEGIN
4986 // END
4987 //
4988 // IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193
4989 // STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
4990 // CAPTION "Wizard97 Property Page - Welcome/Complete"
4991 // FONT 8, "MS Shell Dlg", 0, 0, 0x0
4992 // BEGIN
4993 //    LTEXT           "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8,
4994 //                    195,24
4995 //    LTEXT           "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)",
4996 //                    IDC_STATIC,115,40,195,16
4997 //    LTEXT           "h",IDC_WIZ97_BULLET1,118,64,8,8
4998 //    LTEXT           "List Item 1 (the h is turned into a bullet)",IDC_STATIC,
4999 //                    127,63,122,8
5000 //    LTEXT           "h",IDC_WIZ97_BULLET2,118,79,8,8
5001 //    LTEXT           "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC,
5002 //                    127,78,33,8
5003 //    CONTROL         "&Do not show this Welcome page again",
5004 //                    IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX | 
5005 //                    WS_TABSTOP,115,169,138,10
5006 // END
5007 //
5008 // GUIDELINES DESIGNINFO 
5009 // BEGIN
5010 //    IDD_WIZ97_INTERIOR_BLANK, DIALOG
5011 //    BEGIN
5012 //        LEFTMARGIN, 7
5013 //        RIGHTMARGIN, 310
5014 //        VERTGUIDE, 21
5015 //        VERTGUIDE, 31
5016 //        VERTGUIDE, 286
5017 //        VERTGUIDE, 296
5018 //        TOPMARGIN, 7
5019 //        BOTTOMMARGIN, 136
5020 //        HORZGUIDE, 8
5021 //    END
5022 //
5023 //    IDD_WIZ97_EXTERIOR_BLANK, DIALOG
5024 //    BEGIN
5025 //        RIGHTMARGIN, 310
5026 //        VERTGUIDE, 115
5027 //        VERTGUIDE, 118
5028 //        VERTGUIDE, 127
5029 //        TOPMARGIN, 7
5030 //        BOTTOMMARGIN, 186
5031 //        HORZGUIDE, 8
5032 //        HORZGUIDE, 32
5033 //        HORZGUIDE, 40
5034 //        HORZGUIDE, 169
5035 //    END
5036 // END
5037
5038 ///////////////////////////////////////////////////////////////////////////////
5039 // CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet
5040
5041 class CWizard97SheetWindow : public CPropertySheetWindow
5042 {
5043 public:
5044 // Constructors
5045         CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
5046         { }
5047
5048         CWizard97SheetWindow& operator =(HWND hWnd)
5049         {
5050                 m_hWnd = hWnd;
5051                 return *this;
5052         }
5053
5054 // Operations
5055         HFONT GetExteriorPageTitleFont(void)
5056         {
5057                 ATLASSERT(::IsWindow(m_hWnd));
5058                 return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L);
5059         }
5060
5061         HFONT GetBulletFont(void)
5062         {
5063                 ATLASSERT(::IsWindow(m_hWnd));
5064                 return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L);
5065         }
5066
5067 // Helpers
5068         static UINT GetMessage_GetExteriorPageTitleFont()
5069         {
5070                 static UINT uGetExteriorPageTitleFont = 0;
5071                 if(uGetExteriorPageTitleFont == 0)
5072                 {
5073                         CStaticDataInitCriticalSectionLock lock;
5074                         if(FAILED(lock.Lock()))
5075                         {
5076                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n"));
5077                                 ATLASSERT(FALSE);
5078                                 return 0;
5079                         }
5080
5081                         if(uGetExteriorPageTitleFont == 0)
5082                                 uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12"));
5083
5084                         lock.Unlock();
5085                 }
5086                 ATLASSERT(uGetExteriorPageTitleFont != 0);
5087                 return uGetExteriorPageTitleFont;
5088         }
5089
5090         static UINT GetMessage_GetBulletFont()
5091         {
5092                 static UINT uGetBulletFont = 0;
5093                 if(uGetBulletFont == 0)
5094                 {
5095                         CStaticDataInitCriticalSectionLock lock;
5096                         if(FAILED(lock.Lock()))
5097                         {
5098                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n"));
5099                                 ATLASSERT(FALSE);
5100                                 return 0;
5101                         }
5102
5103                         if(uGetBulletFont == 0)
5104                                 uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5"));
5105
5106                         lock.Unlock();
5107                 }
5108                 ATLASSERT(uGetBulletFont != 0);
5109                 return uGetBulletFont;
5110         }
5111
5112 // Implementation - override to prevent usage
5113         HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
5114         {
5115                 ATLASSERT(FALSE);
5116                 return NULL;
5117         }
5118 };
5119
5120
5121 ///////////////////////////////////////////////////////////////////////////////
5122 // CWizard97SheetImpl - implements a Wizard 97 style wizard sheet
5123
5124 template <class T, class TBase = CWizard97SheetWindow>
5125 class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase >
5126 {
5127 protected:
5128 // Typedefs
5129         typedef CWizard97SheetImpl< T, TBase > thisClass;
5130         typedef CPropertySheetImpl< T, TBase > baseClass;
5131
5132 // Member variables
5133         CFont m_fontExteriorPageTitle;   // Welcome and Completion page title font
5134         CFont m_fontBullet;              // Bullet font (used on static text 'h' to produce a small bullet)
5135         bool m_bReceivedFirstSizeMessage;   
5136
5137 public:
5138         CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
5139                         baseClass(title, uStartPage, hWndParent),
5140                         m_bReceivedFirstSizeMessage(false)
5141         {
5142                 m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP);
5143                 m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE);
5144
5145                 m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP);
5146                 m_psh.dwFlags |= PSH_WIZARD97;
5147
5148                 baseClass::SetHeader(headerBitmap.m_lpstr);
5149                 baseClass::SetWatermark(watermarkBitmap.m_lpstr);
5150         }
5151
5152 // Overrides from base class
5153         void OnSheetInitialized()
5154         {
5155                 T* pT = static_cast<T*>(this);
5156                 pT->_InitializeFonts();
5157
5158                 // We'd like to center the wizard here, but its too early.
5159                 // Instead, we'll do CenterWindow upon our first WM_SIZE message
5160         }
5161
5162 // Initialization
5163         void _InitializeFonts()
5164         {
5165                 // Setup the Title and Bullet Font
5166                 // (Property pages can send the "get external page title font" and "get bullet font" messages)
5167                 // The derived class needs to do the actual SetFont for the dialog items)
5168
5169                 CFontHandle fontThisDialog = this->GetFont();
5170                 CClientDC dcScreen(NULL);
5171
5172                 LOGFONT titleLogFont = {0};
5173                 LOGFONT bulletLogFont = {0};
5174                 fontThisDialog.GetLogFont(&titleLogFont);
5175                 fontThisDialog.GetLogFont(&bulletLogFont);
5176
5177                 // The Wizard 97 Spec recommends to do the Title Font
5178                 // as Verdana Bold, 12pt.
5179                 titleLogFont.lfCharSet = DEFAULT_CHARSET;
5180                 titleLogFont.lfWeight = FW_BOLD;
5181                 SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold"));
5182                 INT titleFontPointSize = 12;
5183                 titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
5184                 m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont);
5185
5186                 // The Wizard 97 Spec recommends to do Bullets by having
5187                 // static text of "h" in the Marlett font.
5188                 bulletLogFont.lfCharSet = DEFAULT_CHARSET;
5189                 bulletLogFont.lfWeight = FW_NORMAL;
5190                 SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett"));
5191                 INT bulletFontSize = 8;
5192                 bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
5193                 m_fontBullet.CreateFontIndirect(&bulletLogFont);
5194         }
5195
5196 // Message Handling
5197         BEGIN_MSG_MAP(thisClass)
5198                 MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont)
5199                 MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont)
5200                 MESSAGE_HANDLER(WM_SIZE, OnSize)
5201                 CHAIN_MSG_MAP(baseClass)
5202         END_MSG_MAP()
5203
5204         LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
5205         {
5206                 return (LRESULT)(HFONT)m_fontExteriorPageTitle;
5207         }
5208
5209         LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
5210         {
5211                 return (LRESULT)(HFONT)m_fontBullet;
5212         }
5213
5214         LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
5215         {
5216                 if(!m_bReceivedFirstSizeMessage)
5217                 {
5218                         m_bReceivedFirstSizeMessage = true;
5219                         this->CenterWindow();
5220                 }
5221
5222                 bHandled = FALSE;
5223                 return 0;
5224         }
5225 };
5226
5227 // for non-customized sheets
5228 class CWizard97Sheet : public CWizard97SheetImpl<CWizard97Sheet>
5229 {
5230 protected:
5231 // Typedefs
5232         typedef CWizard97Sheet thisClass;
5233         typedef CWizard97SheetImpl<CWizard97Sheet> baseClass;
5234
5235 public:
5236         CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
5237                 baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent)
5238         { }
5239
5240         BEGIN_MSG_MAP(thisClass)
5241                 CHAIN_MSG_MAP(baseClass)
5242         END_MSG_MAP()
5243 };
5244
5245
5246 ///////////////////////////////////////////////////////////////////////////////
5247 // CWizard97PageWindow - client side for a Wizard 97 style wizard page
5248
5249 #define WIZARD97_EXTERIOR_CXDLG 317
5250 #define WIZARD97_EXTERIOR_CYDLG 193
5251
5252 #define WIZARD97_INTERIOR_CXDLG 317
5253 #define WIZARD97_INTERIOR_CYDLG 143
5254
5255 class CWizard97PageWindow : public CPropertyPageWindow
5256 {
5257 public:
5258 // Constructors
5259         CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
5260         { }
5261
5262         CWizard97PageWindow& operator =(HWND hWnd)
5263         {
5264                 m_hWnd = hWnd;
5265                 return *this;
5266         }
5267
5268 // Attributes
5269         CWizard97SheetWindow GetPropertySheet() const
5270         {
5271                 ATLASSERT(::IsWindow(m_hWnd));
5272                 return CWizard97SheetWindow(GetParent());
5273         }
5274
5275 // Operations
5276         HFONT GetExteriorPageTitleFont(void)
5277         {
5278                 ATLASSERT(::IsWindow(m_hWnd));
5279                 return GetPropertySheet().GetExteriorPageTitleFont();
5280         }
5281
5282         HFONT GetBulletFont(void)
5283         {
5284                 ATLASSERT(::IsWindow(m_hWnd));
5285                 return GetPropertySheet().GetBulletFont();
5286         }
5287
5288 // Implementation - overrides to prevent usage
5289         HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
5290         {
5291                 ATLASSERT(FALSE);
5292                 return NULL;
5293         }
5294
5295 };
5296
5297
5298 ///////////////////////////////////////////////////////////////////////////////
5299 // CWizard97PageImpl - implements a Wizard 97 style wizard page
5300
5301 template <class T, class TBase = CWizard97PageWindow>
5302 class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase >
5303 {
5304 protected:
5305 // Typedefs
5306         typedef CWizard97PageImpl< T, TBase > thisClass;
5307         typedef CPropertyPageImpl< T, TBase > baseClass;
5308
5309 public:
5310         CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5311         { }
5312
5313 // Message Handling
5314         BEGIN_MSG_MAP(thisClass)
5315                 CHAIN_MSG_MAP(baseClass)
5316         END_MSG_MAP()
5317 };
5318
5319
5320 ///////////////////////////////////////////////////////////////////////////////
5321 // CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page
5322
5323 template <class T, class TBase = CWizard97PageWindow>
5324 class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase >
5325 {
5326 protected:
5327 // Typedefs
5328         typedef CWizard97ExteriorPageImpl< T, TBase > thisClass;
5329         typedef CPropertyPageImpl< T, TBase > baseClass;
5330
5331 public:
5332 // Constructors
5333         CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5334         {
5335                 m_psp.dwFlags |= PSP_HASHELP;
5336                 m_psp.dwFlags |= PSP_HIDEHEADER;
5337         }
5338
5339 // Message Handling
5340         BEGIN_MSG_MAP(thisClass)
5341                 CHAIN_MSG_MAP(baseClass)
5342         END_MSG_MAP()
5343 };
5344
5345
5346 ///////////////////////////////////////////////////////////////////////////////
5347 // CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page
5348
5349 template <class T, class TBase = CWizard97PageWindow>
5350 class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase >
5351 {
5352 protected:
5353 // Typedefs
5354         typedef CWizard97InteriorPageImpl< T, TBase > thisClass;
5355         typedef CPropertyPageImpl< T, TBase > baseClass;
5356
5357 public:
5358 // Constructors
5359         CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5360         {
5361                 m_psp.dwFlags |= PSP_HASHELP;
5362                 m_psp.dwFlags &= ~PSP_HIDEHEADER;
5363                 m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5364
5365                 // Be sure to have the derived class define this in the constructor.
5366                 // We'll default it to something obvious in case its forgotten.
5367                 baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class"));
5368                 baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class."));
5369         }
5370
5371 // Message Handling
5372         BEGIN_MSG_MAP(thisClass)
5373                 CHAIN_MSG_MAP(baseClass)
5374         END_MSG_MAP()
5375 };
5376
5377 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
5378
5379
5380 ///////////////////////////////////////////////////////////////////////////////
5381 // Aero Wizard support
5382
5383 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
5384
5385 ///////////////////////////////////////////////////////////////////////////////
5386 // CAeroWizardFrameWindow - client side for an Aero Wizard frame window
5387
5388 class CAeroWizardFrameWindow : public CPropertySheetWindow
5389 {
5390 public:
5391 // Constructors
5392         CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
5393         { }
5394
5395         CAeroWizardFrameWindow& operator =(HWND hWnd)
5396         {
5397                 m_hWnd = hWnd;
5398                 return *this;
5399         }
5400
5401 // Operations - new, Aero Wizard only
5402         void SetNextText(LPCWSTR lpszText)
5403         {
5404                 ATLASSERT(::IsWindow(m_hWnd));
5405                 ::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText);
5406         }
5407
5408         void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
5409         {
5410                 ATLASSERT(::IsWindow(m_hWnd));
5411                 ::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
5412         }
5413
5414         void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
5415         {
5416                 ATLASSERT(::IsWindow(m_hWnd));
5417                 ::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
5418         }
5419
5420         void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
5421         {
5422                 ATLASSERT(::IsWindow(m_hWnd));
5423                 ::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText);
5424         }
5425 };
5426
5427
5428 ///////////////////////////////////////////////////////////////////////////////
5429 // CAeroWizardFrameImpl - implements an Aero Wizard frame
5430
5431 template <class T, class TBase = CAeroWizardFrameWindow>
5432 class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl<T, TBase >
5433 {
5434 public:
5435 // Constructor
5436         CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) :
5437                 CPropertySheetImpl<T, TBase >(title, uStartPage, hWndParent)
5438         {
5439                 m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD;
5440         }
5441
5442 // Operations
5443         void EnableResizing()
5444         {
5445                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5446                 m_psh.dwFlags |= PSH_RESIZABLE;
5447         }
5448
5449         void UseHeaderBitmap()
5450         {
5451                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5452                 m_psh.dwFlags |= PSH_HEADERBITMAP;
5453         }
5454
5455         void SetNoMargin()
5456         {
5457                 ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5458                 m_psh.dwFlags |= PSH_NOMARGIN;
5459         }
5460
5461 // Override to prevent use
5462         HWND Create(HWND /*hWndParent*/ = NULL)
5463         {
5464                 ATLASSERT(FALSE);   // not supported for Aero Wizard
5465                 return NULL;
5466         }
5467 };
5468
5469
5470 ///////////////////////////////////////////////////////////////////////////////
5471 // CAeroWizardFrame - for non-customized frames
5472
5473 class CAeroWizardFrame : public CAeroWizardFrameImpl<CAeroWizardFrame>
5474 {
5475 public:
5476         CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
5477                 : CAeroWizardFrameImpl<CAeroWizardFrame>(title, uStartPage, hWndParent)
5478         { }
5479
5480         BEGIN_MSG_MAP(CAeroWizardFrame)
5481                 MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl<CAeroWizardFrame>::OnCommand)
5482         END_MSG_MAP()
5483 };
5484
5485
5486 ///////////////////////////////////////////////////////////////////////////////
5487 // CAeroWizardPageWindow - client side for an Aero Wizard page
5488
5489 class CAeroWizardPageWindow : public CPropertyPageWindow
5490 {
5491 public:
5492 // Constructors
5493         CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
5494         { }
5495
5496         CAeroWizardPageWindow& operator =(HWND hWnd)
5497         {
5498                 m_hWnd = hWnd;
5499                 return *this;
5500         }
5501
5502 // Attributes
5503         CAeroWizardFrameWindow GetAeroWizardFrame() const
5504         {
5505                 ATLASSERT(::IsWindow(m_hWnd));
5506                 // This is not really top-level frame window, but it processes all frame messages
5507                 return CAeroWizardFrameWindow(GetParent());
5508         }
5509
5510 // Operations - new, Aero Wizard only
5511         void SetNextText(LPCWSTR lpszText)
5512         {
5513                 ATLASSERT(::IsWindow(m_hWnd));
5514                 ATLASSERT(GetParent() != NULL);
5515                 GetAeroWizardFrame().SetNextText(lpszText);
5516         }
5517
5518         void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
5519         {
5520                 ATLASSERT(::IsWindow(m_hWnd));
5521                 ATLASSERT(GetParent() != NULL);
5522                 GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates);
5523         }
5524
5525         void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
5526         {
5527                 ATLASSERT(::IsWindow(m_hWnd));
5528                 ATLASSERT(GetParent() != NULL);
5529                 GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates);
5530         }
5531
5532         void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
5533         {
5534                 ATLASSERT(::IsWindow(m_hWnd));
5535                 ATLASSERT(GetParent() != NULL);
5536                 GetAeroWizardFrame().SetButtonText(dwButton, lpszText);
5537         }
5538 };
5539
5540
5541 ///////////////////////////////////////////////////////////////////////////////
5542 // CAeroWizardPageImpl - implements an Aero Wizard page
5543
5544 template <class T, class TBase = CAeroWizardPageWindow>
5545 class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl<T, TBase >
5546 {
5547 public:
5548         CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<T, TBase >(title)
5549         { }
5550 };
5551
5552
5553 ///////////////////////////////////////////////////////////////////////////////
5554 // CAeroWizardPage - for non-customized pages
5555
5556 template <WORD t_wDlgTemplateID>
5557 class CAeroWizardPage : public CAeroWizardPageImpl<CAeroWizardPage<t_wDlgTemplateID> >
5558 {
5559 public:
5560         enum { IDD = t_wDlgTemplateID };
5561
5562         CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl<CAeroWizardPage>(title)
5563         { }
5564
5565         DECLARE_EMPTY_MSG_MAP()
5566 };
5567
5568
5569 #ifndef _ATL_NO_HOSTING
5570
5571 // Note: You must #include <atlhost.h> to use these classes
5572
5573 ///////////////////////////////////////////////////////////////////////////////
5574 // CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls
5575
5576 template <class T, class TBase = CAeroWizardPageWindow>
5577 class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase >
5578 {
5579 public:
5580         CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title)
5581         { }
5582 };
5583
5584
5585 ///////////////////////////////////////////////////////////////////////////////
5586 // CAeroWizardAxPage - for non-customized pages
5587
5588 template <WORD t_wDlgTemplateID>
5589 class CAeroWizardAxPage : public CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >
5590 {
5591 public:
5592         enum { IDD = t_wDlgTemplateID };
5593
5594         CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl<CAeroWizardAxPage>(title)
5595         { }
5596
5597 #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
5598         // not empty so we handle accelerators/create controls
5599         BEGIN_MSG_MAP(CAeroWizardAxPage)
5600                 CHAIN_MSG_MAP(CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >)
5601         END_MSG_MAP()
5602 #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5603         DECLARE_EMPTY_MSG_MAP()
5604 #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5605 };
5606
5607 #endif // _ATL_NO_HOSTING
5608
5609 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
5610
5611
5612 ///////////////////////////////////////////////////////////////////////////////
5613 // TaskDialog support
5614
5615 #if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
5616
5617 ///////////////////////////////////////////////////////////////////////////////
5618 // AtlTaskDialog - support for TaskDialog() function
5619
5620 inline int AtlTaskDialog(HWND hWndParent, 
5621                          ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText, 
5622                          TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL)
5623 {
5624         int nRet = -1;
5625
5626 #ifdef _WTL_TASKDIALOG_DIRECT
5627         USES_CONVERSION;
5628         HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), T2CW(WindowTitle.m_lpstr), T2CW(MainInstructionText.m_lpstr), T2CW(ContentText.m_lpstr), dwCommonButtons, T2CW(Icon.m_lpstr), &nRet);
5629         ATLVERIFY(SUCCEEDED(hRet));
5630 #else
5631         // This allows apps to run on older versions of Windows
5632         typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton);
5633
5634         HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
5635         if(m_hCommCtrlDLL != NULL)
5636         {
5637                 PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog");
5638                 if(pfnTaskDialog != NULL)
5639                 {
5640                         USES_CONVERSION;
5641                         HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), T2CW(WindowTitle.m_lpstr), T2CW(MainInstructionText.m_lpstr), T2CW(ContentText.m_lpstr), dwCommonButtons, T2CW(Icon.m_lpstr), &nRet);
5642                         ATLVERIFY(SUCCEEDED(hRet));
5643                 }
5644
5645                 ::FreeLibrary(m_hCommCtrlDLL);
5646         }
5647 #endif
5648
5649         return nRet;
5650 }
5651
5652
5653 ///////////////////////////////////////////////////////////////////////////////
5654 // CTaskDialogConfig - TASKDIALOGCONFIG wrapper
5655
5656 class CTaskDialogConfig : public TASKDIALOGCONFIG
5657 {
5658 public:
5659 // Constructor
5660         CTaskDialogConfig()
5661         {
5662                 Init();
5663         }
5664
5665         void Init()
5666         {
5667                 memset(this, 0, sizeof(TASKDIALOGCONFIG));   // initialize structure to 0/NULL
5668                 this->cbSize = sizeof(TASKDIALOGCONFIG);
5669                 this->hInstance = ModuleHelper::GetResourceInstance();
5670         }
5671
5672 // Operations - setting values
5673         // common buttons
5674         void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
5675         {
5676                 this->dwCommonButtons = dwCommonButtons;
5677         }
5678
5679         // window title text
5680         void SetWindowTitle(UINT nID)
5681         {
5682                 this->pszWindowTitle = MAKEINTRESOURCEW(nID);
5683         }
5684
5685         void SetWindowTitle(LPCWSTR lpstrWindowTitle)
5686         {
5687                 this->pszWindowTitle = lpstrWindowTitle;
5688         }
5689
5690         // main icon
5691         void SetMainIcon(HICON hIcon)
5692         {
5693                 this->dwFlags |= TDF_USE_HICON_MAIN;
5694                 this->hMainIcon = hIcon;
5695         }
5696
5697         void SetMainIcon(UINT nID)
5698         {
5699                 this->dwFlags &= ~TDF_USE_HICON_MAIN;
5700                 this->pszMainIcon = MAKEINTRESOURCEW(nID);
5701         }
5702
5703         void SetMainIcon(LPCWSTR lpstrMainIcon)
5704         {
5705                 this->dwFlags &= ~TDF_USE_HICON_MAIN;
5706                 this->pszMainIcon = lpstrMainIcon;
5707         }
5708
5709         // main instruction text
5710         void SetMainInstructionText(UINT nID)
5711         {
5712                 this->pszMainInstruction = MAKEINTRESOURCEW(nID);
5713         }
5714
5715         void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
5716         {
5717                 this->pszMainInstruction = lpstrMainInstruction;
5718         }
5719
5720         // content text
5721         void SetContentText(UINT nID)
5722         {
5723                 this->pszContent = MAKEINTRESOURCEW(nID);
5724         }
5725
5726         void SetContentText(LPCWSTR lpstrContent)
5727         {
5728                 this->pszContent = lpstrContent;
5729         }
5730
5731         // buttons
5732         void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)
5733         {
5734                 this->pButtons = pButtons;
5735                 this->cButtons = cButtons;
5736                 if(nDefaultButton != 0)
5737                         this->nDefaultButton = nDefaultButton;
5738         }
5739
5740         void SetDefaultButton(int nDefaultButton)
5741         {
5742                 this->nDefaultButton = nDefaultButton;
5743         }
5744
5745         // radio buttons
5746         void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)
5747         {
5748                 this->pRadioButtons = pRadioButtons;
5749                 this->cRadioButtons = cRadioButtons;
5750                 if(nDefaultRadioButton != 0)
5751                         this->nDefaultRadioButton = nDefaultRadioButton;
5752         }
5753
5754         void SetDefaultRadioButton(int nDefaultRadioButton)
5755         {
5756                 this->nDefaultRadioButton = nDefaultRadioButton;
5757         }
5758
5759         // verification text
5760         void SetVerificationText(UINT nID)
5761         {
5762                 this->pszVerificationText = MAKEINTRESOURCEW(nID);
5763         }
5764
5765         void SetVerificationText(LPCWSTR lpstrVerificationText)
5766         {
5767                 this->pszVerificationText = lpstrVerificationText;
5768         }
5769
5770         // expanded information text
5771         void SetExpandedInformationText(UINT nID)
5772         {
5773                 this->pszExpandedInformation = MAKEINTRESOURCEW(nID);
5774         }
5775
5776         void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
5777         {
5778                 this->pszExpandedInformation = lpstrExpandedInformation;
5779         }
5780
5781         // expanded control text
5782         void SetExpandedControlText(UINT nID)
5783         {
5784                 this->pszExpandedControlText = MAKEINTRESOURCEW(nID);
5785         }
5786
5787         void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
5788         {
5789                 this->pszExpandedControlText = lpstrExpandedControlText;
5790         }
5791
5792         // collapsed control text
5793         void SetCollapsedControlText(UINT nID)
5794         {
5795                 this->pszCollapsedControlText = MAKEINTRESOURCEW(nID);
5796         }
5797
5798         void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
5799         {
5800                 this->pszCollapsedControlText = lpstrCollapsedControlText;
5801         }
5802
5803         // footer icon
5804         void SetFooterIcon(HICON hIcon)
5805         {
5806                 this->dwFlags |= TDF_USE_HICON_FOOTER;
5807                 this->hFooterIcon = hIcon;
5808         }
5809
5810         void SetFooterIcon(UINT nID)
5811         {
5812                 this->dwFlags &= ~TDF_USE_HICON_FOOTER;
5813                 this->pszFooterIcon = MAKEINTRESOURCEW(nID);
5814         }
5815
5816         void SetFooterIcon(LPCWSTR lpstrFooterIcon)
5817         {
5818                 this->dwFlags &= ~TDF_USE_HICON_FOOTER;
5819                 this->pszFooterIcon = lpstrFooterIcon;
5820         }
5821
5822         // footer text
5823         void SetFooterText(UINT nID)
5824         {
5825                 this->pszFooter = MAKEINTRESOURCEW(nID);
5826         }
5827
5828         void SetFooterText(LPCWSTR lpstrFooterText)
5829         {
5830                 this->pszFooter = lpstrFooterText;
5831         }
5832
5833         // width (in DLUs)
5834         void SetWidth(UINT cxWidth)
5835         {
5836                 this->cxWidth = cxWidth;
5837         }
5838
5839         // modify flags
5840         void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
5841         {
5842                 this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd;
5843         }
5844 };
5845
5846
5847 ///////////////////////////////////////////////////////////////////////////////
5848 // CTaskDialogImpl - implements a Task Dialog
5849
5850 template <class T>
5851 class ATL_NO_VTABLE CTaskDialogImpl
5852 {
5853 public:
5854         CTaskDialogConfig m_tdc;
5855         HWND m_hWnd;   // used only in callback functions
5856
5857 // Constructor
5858         CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL)
5859         {
5860                 m_tdc.hwndParent = hWndParent;
5861                 m_tdc.pfCallback = T::TaskDialogCallback;
5862                 m_tdc.lpCallbackData = (LONG_PTR)static_cast<T*>(this);
5863         }
5864
5865 // Operations
5866         HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL)
5867         {
5868                 if(m_tdc.hwndParent == NULL)
5869                         m_tdc.hwndParent = hWndParent;
5870
5871 #ifdef _WTL_TASKDIALOG_DIRECT
5872                 return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
5873 #else
5874
5875                 // This allows apps to run on older versions of Windows
5876                 typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked);
5877
5878                 HRESULT hRet = E_UNEXPECTED;
5879                 HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
5880                 if(m_hCommCtrlDLL != NULL)
5881                 {
5882                         PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect");
5883                         if(pfnTaskDialogIndirect != NULL)
5884                                 hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
5885
5886                         ::FreeLibrary(m_hCommCtrlDLL);
5887                 }
5888
5889                 return hRet;
5890 #endif
5891         }
5892
5893 // Operations - setting values of TASKDIALOGCONFIG
5894         // common buttons
5895         void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
5896         {       m_tdc.SetCommonButtons(dwCommonButtons); }
5897         // window title text
5898         void SetWindowTitle(UINT nID)
5899         {       m_tdc.SetWindowTitle(nID); }
5900         void SetWindowTitle(LPCWSTR lpstrWindowTitle)
5901         {       m_tdc.SetWindowTitle(lpstrWindowTitle); }
5902         // main icon
5903         void SetMainIcon(HICON hIcon)
5904         {       m_tdc.SetMainIcon(hIcon); }
5905         void SetMainIcon(UINT nID)
5906         {       m_tdc.SetMainIcon(nID); }
5907         void SetMainIcon(LPCWSTR lpstrMainIcon)
5908         {       m_tdc.SetMainIcon(lpstrMainIcon); }
5909         // main instruction text
5910         void SetMainInstructionText(UINT nID)
5911         {       m_tdc.SetMainInstructionText(nID); }
5912         void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
5913         {       m_tdc.SetMainInstructionText(lpstrMainInstruction); }
5914         // content text
5915         void SetContentText(UINT nID)
5916         {       m_tdc.SetContentText(nID); }
5917         void SetContentText(LPCWSTR lpstrContent)
5918         {       m_tdc.SetContentText(lpstrContent); }
5919         // buttons
5920         void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)
5921         {       m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); }
5922         void SetDefaultButton(int nDefaultButton)
5923         {       m_tdc.SetDefaultButton(nDefaultButton); }
5924         // radio buttons
5925         void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)
5926         {       m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); }
5927         void SetDefaultRadioButton(int nDefaultRadioButton)
5928         {       m_tdc.SetDefaultRadioButton(nDefaultRadioButton); }
5929         // verification text
5930         void SetVerificationText(UINT nID)
5931         {       m_tdc.SetVerificationText(nID); }
5932         void SetVerificationText(LPCWSTR lpstrVerificationText)
5933         {       m_tdc.SetVerificationText(lpstrVerificationText); }
5934         // expanded information text
5935         void SetExpandedInformationText(UINT nID)
5936         {       m_tdc.SetExpandedInformationText(nID); }
5937         void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
5938         {       m_tdc.SetExpandedInformationText(lpstrExpandedInformation); }
5939         // expanded control text
5940         void SetExpandedControlText(UINT nID)
5941         {       m_tdc.SetExpandedControlText(nID); }
5942         void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
5943         {       m_tdc.SetExpandedControlText(lpstrExpandedControlText); }
5944         // collapsed control text
5945         void SetCollapsedControlText(UINT nID)
5946         {       m_tdc.SetCollapsedControlText(nID); }
5947         void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
5948         {       m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); }
5949         // footer icon
5950         void SetFooterIcon(HICON hIcon)
5951         {       m_tdc.SetFooterIcon(hIcon); }
5952         void SetFooterIcon(UINT nID)
5953         {       m_tdc.SetFooterIcon(nID); }
5954         void SetFooterIcon(LPCWSTR lpstrFooterIcon)
5955         {       m_tdc.SetFooterIcon(lpstrFooterIcon); }
5956         // footer text
5957         void SetFooterText(UINT nID)
5958         {       m_tdc.SetFooterText(nID); }
5959         void SetFooterText(LPCWSTR lpstrFooterText)
5960         {       m_tdc.SetFooterText(lpstrFooterText); }
5961         // width (in DLUs)
5962         void SetWidth(UINT cxWidth)
5963         {       m_tdc.SetWidth(cxWidth); }
5964         // modify flags
5965         void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
5966         {       m_tdc.ModifyFlags(dwRemove, dwAdd); }
5967
5968 // Implementation
5969         static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData)
5970         {
5971                 T* pT = (T*)lpRefData;
5972                 ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd);
5973
5974                 BOOL bRet = FALSE;
5975                 switch(uMsg)
5976                 {
5977                 case TDN_DIALOG_CONSTRUCTED:
5978                         pT->m_hWnd = hWnd;
5979                         pT->OnDialogConstructed();
5980                         break;
5981                 case TDN_CREATED:
5982                         pT->OnCreated();
5983                         break;
5984                 case TDN_BUTTON_CLICKED:
5985                         bRet = pT->OnButtonClicked((int)wParam);
5986                         break;
5987                 case TDN_RADIO_BUTTON_CLICKED:
5988                         pT->OnRadioButtonClicked((int)wParam);
5989                         break;
5990                 case TDN_HYPERLINK_CLICKED:
5991                         pT->OnHyperlinkClicked((LPCWSTR)lParam);
5992                         break;
5993                 case TDN_EXPANDO_BUTTON_CLICKED:
5994                         pT->OnExpandoButtonClicked((wParam != 0));
5995                         break;
5996                 case TDN_VERIFICATION_CLICKED:
5997                         pT->OnVerificationClicked((wParam != 0));
5998                         break;
5999                 case TDN_HELP:
6000                         pT->OnHelp();
6001                         break;
6002                 case TDN_TIMER:
6003                         bRet = pT->OnTimer((DWORD)wParam);
6004                         break;
6005                 case TDN_NAVIGATED:
6006                         pT->OnNavigated();
6007                         break;
6008                 case TDN_DESTROYED:
6009                         pT->OnDestroyed();
6010                         pT->m_hWnd = NULL;
6011                         break;
6012                 default:
6013                         ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n"));
6014                         break;
6015                 }
6016
6017                 return (HRESULT)bRet;
6018         }
6019
6020 // Overrideables - notification handlers
6021         void OnDialogConstructed()
6022         {
6023         }
6024
6025         void OnCreated()
6026         {
6027         }
6028
6029         BOOL OnButtonClicked(int /*nButton*/)
6030         {
6031                 return FALSE;   // don't prevent dialog to close
6032         }
6033
6034         void OnRadioButtonClicked(int /*nRadioButton*/)
6035         {
6036         }
6037
6038         void OnHyperlinkClicked(LPCWSTR /*pszHREF*/)
6039         {
6040         }
6041
6042         void OnExpandoButtonClicked(bool /*bExpanded*/)
6043         {
6044         }
6045
6046         void OnVerificationClicked(bool /*bChecked*/)
6047         {
6048         }
6049
6050         void OnHelp()
6051         {
6052         }
6053
6054         BOOL OnTimer(DWORD /*dwTickCount*/)
6055         {
6056                 return FALSE;   // don't reset counter
6057         }
6058
6059         void OnNavigated()
6060         {
6061         }
6062
6063         void OnDestroyed()
6064         {
6065         }
6066
6067 // Commands - valid to call only from handlers
6068         void NavigatePage(TASKDIALOGCONFIG& tdc)
6069         {
6070                 ATLASSERT(m_hWnd != NULL);
6071
6072                 tdc.cbSize = sizeof(TASKDIALOGCONFIG);
6073                 if(tdc.hwndParent == NULL)
6074                         tdc.hwndParent = m_tdc.hwndParent;
6075                 tdc.pfCallback = m_tdc.pfCallback;
6076                 tdc.lpCallbackData = m_tdc.lpCallbackData;
6077                 (TASKDIALOGCONFIG)m_tdc = tdc;
6078
6079                 ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc);
6080         }
6081
6082         // modify TASKDIALOGCONFIG values, then call this to update task dialog
6083         void NavigatePage()
6084         {
6085                 ATLASSERT(m_hWnd != NULL);
6086                 ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc);
6087         }
6088
6089         void ClickButton(int nButton)
6090         {
6091                 ATLASSERT(m_hWnd != NULL);
6092                 ::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L);
6093         }
6094
6095         void SetMarqueeProgressBar(BOOL bMarquee)
6096         {
6097                 ATLASSERT(m_hWnd != NULL);
6098                 ::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L);
6099         }
6100
6101         BOOL SetProgressBarState(int nNewState)
6102         {
6103                 ATLASSERT(m_hWnd != NULL);
6104                 return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L);
6105         }
6106
6107         DWORD SetProgressBarRange(int nMinRange, int nMaxRange)
6108         {
6109                 ATLASSERT(m_hWnd != NULL);
6110                 return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange));
6111         }
6112
6113         int SetProgressBarPos(int nNewPos)
6114         {
6115                 ATLASSERT(m_hWnd != NULL);
6116                 return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L);
6117         }
6118
6119         BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed)
6120         {
6121                 ATLASSERT(m_hWnd != NULL);
6122                 return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed);
6123         }
6124
6125         void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
6126         {
6127                 ATLASSERT(m_hWnd != NULL);
6128                 ::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText);
6129         }
6130
6131         void ClickRadioButton(int nRadioButton)
6132         {
6133                 ATLASSERT(m_hWnd != NULL);
6134                 ::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L);
6135         }
6136
6137         void EnableButton(int nButton, BOOL bEnable)
6138         {
6139                 ATLASSERT(m_hWnd != NULL);
6140                 ::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable);
6141         }
6142
6143         void EnableRadioButton(int nButton, BOOL bEnable)
6144         {
6145                 ATLASSERT(m_hWnd != NULL);
6146                 ::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable);
6147         }
6148
6149         void ClickVerification(BOOL bCheck, BOOL bFocus)
6150         {
6151                 ATLASSERT(m_hWnd != NULL);
6152                 ::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus);
6153         }
6154
6155         void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
6156         {
6157                 ATLASSERT(m_hWnd != NULL);
6158                 ::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText);
6159         }
6160
6161         void SetButtonElevationRequiredState(int nButton, BOOL bElevation)
6162         {
6163                 ATLASSERT(m_hWnd != NULL);
6164                 ::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation);
6165         }
6166
6167         void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon)
6168         {
6169                 ATLASSERT(m_hWnd != NULL);
6170 #ifdef _DEBUG
6171                 if(element == TDIE_ICON_MAIN)
6172                         ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0);
6173                 else if(element == TDIE_ICON_FOOTER)
6174                         ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0);
6175 #endif // _DEBUG
6176                 ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon);
6177         }
6178
6179         void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon)
6180         {
6181                 ATLASSERT(m_hWnd != NULL);
6182 #ifdef _DEBUG
6183                 if(element == TDIE_ICON_MAIN)
6184                         ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0);
6185                 else if(element == TDIE_ICON_FOOTER)
6186                         ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0);
6187 #endif // _DEBUG
6188                 ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon);
6189         }
6190 };
6191
6192
6193 ///////////////////////////////////////////////////////////////////////////////
6194 // CTaskDialog - for non-customized task dialogs
6195
6196 class CTaskDialog : public CTaskDialogImpl<CTaskDialog>
6197 {
6198 public:
6199         CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl<CTaskDialog>(hWndParent)
6200         {
6201                 m_tdc.pfCallback = NULL;
6202         }
6203 };
6204
6205 #endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
6206
6207 }; // namespace WTL
6208
6209 #endif // __ATLDLGS_H__