├── D ├── D │ ├── D.h │ ├── D.rc │ ├── 2.png │ ├── 3.png │ ├── D.ico │ ├── bk1.png │ ├── small.ico │ ├── stdafx.h │ ├── Resource.h │ ├── stdafx.cpp │ ├── targetver.h │ ├── ImageParser.h │ ├── D.vcxproj.filters │ ├── ImageParser.cpp │ ├── wtl │ │ ├── atlresce.h │ │ ├── atlres.h │ │ ├── atldwm.h │ │ ├── atlwinx.h │ │ ├── atlddx.h │ │ ├── atlsplit.h │ │ ├── atlfind.h │ │ ├── atlprint.h │ │ └── atltheme.h │ ├── D.vcxproj │ └── D.cpp ├── D.v12.suo ├── Debug │ ├── 2.png │ ├── 3.png │ ├── D.exe │ └── bk1.png ├── .vs │ └── D │ │ └── v14 │ │ └── .suo └── D.sln └── README.md /D/D/D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Direct2D-Layered-Window 2 | 3 | Direct2D实现Layered异形半透明窗口 4 | -------------------------------------------------------------------------------- /D/D/D.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/D.rc -------------------------------------------------------------------------------- /D/D/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/2.png -------------------------------------------------------------------------------- /D/D/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/3.png -------------------------------------------------------------------------------- /D/D/D.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/D.ico -------------------------------------------------------------------------------- /D/D.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D.v12.suo -------------------------------------------------------------------------------- /D/D/bk1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/bk1.png -------------------------------------------------------------------------------- /D/D/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/small.ico -------------------------------------------------------------------------------- /D/D/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/stdafx.h -------------------------------------------------------------------------------- /D/Debug/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/Debug/2.png -------------------------------------------------------------------------------- /D/Debug/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/Debug/3.png -------------------------------------------------------------------------------- /D/Debug/D.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/Debug/D.exe -------------------------------------------------------------------------------- /D/D/Resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/Resource.h -------------------------------------------------------------------------------- /D/D/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/stdafx.cpp -------------------------------------------------------------------------------- /D/D/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/D/targetver.h -------------------------------------------------------------------------------- /D/Debug/bk1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/Debug/bk1.png -------------------------------------------------------------------------------- /D/.vs/D/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/Direct2D-Layered-Window/HEAD/D/.vs/D/v14/.suo -------------------------------------------------------------------------------- /D/D/ImageParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _IMAGEPARSER_H_ 2 | #define _IMAGEPARSER_H_ 3 | 4 | #include 5 | #include 6 | class ImageParser 7 | { 8 | public: 9 | HRESULT LoadImageFile(ID2D1RenderTarget *pRenderTarget, IWICImagingFactory *pIWICFactory, 10 | PCWSTR uri, 11 | UINT destinationWidth, 12 | UINT destinationHeight, 13 | ID2D1Bitmap **ppBitmap, 14 | IWICBitmap **ppWicBitma); 15 | }; 16 | #endif -------------------------------------------------------------------------------- /D/D.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D", "D\D.vcxproj", "{AA5B939B-6415-472F-8B5B-3A6E3CA00215}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {AA5B939B-6415-472F-8B5B-3A6E3CA00215}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {AA5B939B-6415-472F-8B5B-3A6E3CA00215}.Debug|Win32.Build.0 = Debug|Win32 16 | {AA5B939B-6415-472F-8B5B-3A6E3CA00215}.Release|Win32.ActiveCfg = Release|Win32 17 | {AA5B939B-6415-472F-8B5B-3A6E3CA00215}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /D/D/D.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 头文件 32 | 33 | 34 | 源文件 35 | 36 | 37 | 38 | 39 | 源文件 40 | 41 | 42 | 源文件 43 | 44 | 45 | 源文件 46 | 47 | 48 | 49 | 50 | 资源文件 51 | 52 | 53 | 54 | 55 | 资源文件 56 | 57 | 58 | 资源文件 59 | 60 | 61 | -------------------------------------------------------------------------------- /D/D/ImageParser.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdafx.h" 3 | #include "ImageParser.h" 4 | 5 | HRESULT ImageParser::LoadImageFile(ID2D1RenderTarget *pRenderTarget, IWICImagingFactory *pIWICFactory, 6 | PCWSTR uri, 7 | UINT destinationWidth, 8 | UINT destinationHeight, 9 | ID2D1Bitmap **ppBitmap, 10 | IWICBitmap **ppWicBitmap) 11 | { 12 | HRESULT hRet = S_OK; 13 | 14 | IWICBitmapDecoder *pDecoder = nullptr; 15 | IWICBitmapFrameDecode *pSource = nullptr; 16 | IWICStream *pStream = nullptr; 17 | IWICFormatConverter *pConverter = nullptr; 18 | IWICBitmapScaler *pScaler = nullptr; 19 | 20 | hRet = pIWICFactory->CreateDecoderFromFilename(uri, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder); 21 | if (SUCCEEDED(hRet)) 22 | { 23 | hRet = pDecoder->GetFrame(0, &pSource); 24 | } 25 | 26 | if (SUCCEEDED(hRet)) 27 | { 28 | hRet = pIWICFactory->CreateFormatConverter(&pConverter); 29 | } 30 | 31 | 32 | UINT originalWidth, originalHeight; 33 | hRet = pSource->GetSize(&originalWidth, &originalHeight); 34 | if (SUCCEEDED(hRet)) 35 | { 36 | if (destinationWidth != 0 && destinationHeight != 0) 37 | { 38 | originalWidth = destinationWidth; 39 | originalHeight = destinationHeight; 40 | } 41 | 42 | hRet = pIWICFactory->CreateBitmapScaler(&pScaler); 43 | if (SUCCEEDED(hRet)) 44 | { 45 | hRet = pScaler->Initialize(pSource, originalWidth, originalHeight, WICBitmapInterpolationModeCubic); 46 | } 47 | 48 | if (SUCCEEDED(hRet)) 49 | { 50 | hRet = pConverter->Initialize(pScaler, GUID_WICPixelFormat32bppPBGRA, 51 | WICBitmapDitherTypeNone, 52 | nullptr, 53 | 0.f, 54 | WICBitmapPaletteTypeMedianCut); 55 | } 56 | } 57 | 58 | if (SUCCEEDED(hRet)) 59 | { 60 | hRet = pRenderTarget->CreateBitmapFromWicBitmap(pConverter, nullptr, ppBitmap); 61 | } 62 | 63 | if (SUCCEEDED(hRet)) 64 | { 65 | hRet = pIWICFactory->CreateBitmapFromSource(pConverter, WICBitmapCacheOnLoad, ppWicBitmap); 66 | } 67 | SAFE_RELEASE(pDecoder); 68 | SAFE_RELEASE(pSource); 69 | SAFE_RELEASE(pStream); 70 | SAFE_RELEASE(pConverter); 71 | SAFE_RELEASE(pScaler); 72 | 73 | return hRet; 74 | } -------------------------------------------------------------------------------- /D/D/wtl/atlresce.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLRESCE_H__ 13 | #define __ATLRESCE_H__ 14 | 15 | #pragma once 16 | 17 | #ifndef _WIN32_WCE 18 | #error atlresCE.h is only for Windows CE 19 | #endif 20 | 21 | 22 | #ifdef RC_INVOKED 23 | #ifndef _INC_WINDOWS 24 | 25 | #define VS_VERSION_INFO 1 26 | 27 | #ifdef APSTUDIO_INVOKED 28 | #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols 29 | #endif // APSTUDIO_INVOKED 30 | 31 | #ifndef WINVER 32 | #define WINVER 0x0400 // default to Windows Version 4.0 33 | #endif // !WINVER 34 | 35 | #if !defined(WCEOLE_ENABLE_DIALOGEX) 36 | #define DIALOGEX DIALOG DISCARDABLE 37 | #endif 38 | 39 | #include 40 | #define SHMENUBAR RCDATA 41 | 42 | #if defined(SHELLSDK_MODULES_AYGSHELL) 43 | #include 44 | #else 45 | #define NOMENU 0xFFFF 46 | #define IDS_SHNEW 1 47 | #define IDM_SHAREDNEW 10 48 | #define IDM_SHAREDNEWDEFAULT 11 49 | #endif 50 | #ifndef I_IMAGENONE 51 | #define I_IMAGENONE (-2) 52 | #endif 53 | 54 | #include 55 | 56 | #endif // !_INC_WINDOWS 57 | #endif // RC_INVOKED 58 | 59 | #include "atlres.h" 60 | 61 | #ifdef APSTUDIO_INVOKED 62 | #undef APSTUDIO_HIDDEN_SYMBOLS 63 | #endif // APSTUDIO_INVOKED 64 | 65 | // Visual Studio dialog editor bug fix 66 | #ifndef DS_FIXEDSYS 67 | #define DS_FIXEDSYS 0 68 | #endif 69 | 70 | #define IDC_INFOSTATIC 0xFFFE // == IDC_STATIC -1 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | // Smartphone and PPC 2005 Resource IDs 74 | 75 | // Command and associated string resource IDs 76 | #define ID_MENU_OK 0xE790 77 | #define ID_MENU_CANCEL 0xE791 78 | #define ID_MENU 0xE792 79 | #define ID_ACTION 0xE793 80 | #define ID_VIEW_FULLSCREEN 0xE802 81 | 82 | // MenuBar resource IDs 83 | #define ATL_IDM_MENU_DONE 0xE701 84 | #define ATL_IDM_MENU_CANCEL 0xE702 85 | #define ATL_IDM_MENU_DONECANCEL 0xE703 86 | 87 | // Default device MenuBar control ID and MenuBar resource ID 88 | #define ATL_IDW_MENU_BAR 0xE802 89 | 90 | // SmartPhone spinned controls ID offset for CSpinCtrl 91 | #define ATL_IDW_SPIN_ID 9999 92 | 93 | #endif // __ATLRESCE_H__ 94 | -------------------------------------------------------------------------------- /D/D/D.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {AA5B939B-6415-472F-8B5B-3A6E3CA00215} 15 | Win32Proj 16 | D 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 54 | false 55 | .\wtl;%(AdditionalIncludeDirectories) 56 | 57 | 58 | Windows 59 | true 60 | d2d1.lib;dxguid.lib;windowscodecs.lib;msimg32.lib;%(AdditionalDependencies) 61 | 62 | 63 | 64 | 65 | Level3 66 | Use 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 71 | true 72 | 73 | 74 | Windows 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Create 95 | Create 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /D/D/wtl/atlres.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLRES_H__ 13 | #define __ATLRES_H__ 14 | 15 | #pragma once 16 | 17 | #if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__) 18 | #error Use atlresCE.h instead of atlres.h for Windows CE 19 | #endif 20 | 21 | 22 | #ifdef RC_INVOKED 23 | #ifndef _INC_WINDOWS 24 | 25 | #define _INC_WINDOWS 26 | 27 | #ifndef _WIN32_WCE 28 | #define VS_VERSION_INFO 1 29 | 30 | #ifdef APSTUDIO_INVOKED 31 | #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols 32 | #endif // APSTUDIO_INVOKED 33 | 34 | #ifndef WINVER 35 | #define WINVER 0x0400 // default to Windows Version 4.0 36 | #endif // !WINVER 37 | 38 | #include 39 | 40 | // operation messages sent to DLGINIT 41 | #define LB_ADDSTRING (WM_USER+1) 42 | #define CB_ADDSTRING (WM_USER+3) 43 | #endif // !_WIN32_WCE 44 | 45 | #ifdef APSTUDIO_INVOKED 46 | #undef APSTUDIO_HIDDEN_SYMBOLS 47 | #endif // APSTUDIO_INVOKED 48 | 49 | #ifdef IDC_STATIC 50 | #undef IDC_STATIC 51 | #endif // IDC_STATIC 52 | #define IDC_STATIC (-1) 53 | 54 | #endif // !_INC_WINDOWS 55 | #endif // RC_INVOKED 56 | 57 | #ifdef APSTUDIO_INVOKED 58 | #define APSTUDIO_HIDDEN_SYMBOLS 59 | #endif // APSTUDIO_INVOKED 60 | 61 | /////////////////////////////////////////////////////////////////////////////// 62 | // ATL resource types 63 | 64 | #ifndef RC_INVOKED 65 | #define RT_DLGINIT MAKEINTRESOURCE(240) 66 | #define RT_TOOLBAR MAKEINTRESOURCE(241) 67 | #endif // RC_INVOKED 68 | 69 | /////////////////////////////////////////////////////////////////////////////// 70 | 71 | #ifdef APSTUDIO_INVOKED 72 | #undef APSTUDIO_HIDDEN_SYMBOLS 73 | #endif // APSTUDIO_INVOKED 74 | 75 | /////////////////////////////////////////////////////////////////////////////// 76 | // Standard window components 77 | 78 | #define ID_SEPARATOR 0 // special separator value 79 | #define ID_DEFAULT_PANE 0 // default status bar pane 80 | 81 | #ifndef RC_INVOKED // code only 82 | // standard control bars (IDW = window ID) 83 | #define ATL_IDW_TOOLBAR 0xE800 // main Toolbar for window 84 | #define ATL_IDW_STATUS_BAR 0xE801 // Status bar window 85 | #define ATL_IDW_COMMAND_BAR 0xE802 // Command bar window 86 | 87 | // parts of a frame window 88 | #define ATL_IDW_CLIENT 0xE900 89 | #define ATL_IDW_PANE_FIRST 0xE900 // first pane (256 max) 90 | #define ATL_IDW_PANE_LAST 0xE9FF 91 | #define ATL_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max) 92 | #define ATL_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max) 93 | 94 | #define ATL_IDW_SIZE_BOX 0xEA20 // size box for splitters 95 | #define ATL_IDW_PANE_SAVE 0xEA21 // to shift ATL_IDW_PANE_FIRST 96 | 97 | // bands for a rebar 98 | #define ATL_IDW_BAND_FIRST 0xEB00 99 | #define ATL_IDW_BAND_LAST 0xEBFF 100 | #endif // !RC_INVOKED 101 | 102 | /////////////////////////////////////////////////////////////////////////////// 103 | // Standard Commands 104 | 105 | // File commands 106 | #define ID_FILE_NEW 0xE100 107 | #define ID_FILE_OPEN 0xE101 108 | #define ID_FILE_CLOSE 0xE102 109 | #define ID_FILE_SAVE 0xE103 110 | #define ID_FILE_SAVE_AS 0xE104 111 | #define ID_FILE_PAGE_SETUP 0xE105 112 | #define ID_FILE_PRINT_SETUP 0xE106 113 | #define ID_FILE_PRINT 0xE107 114 | #define ID_FILE_PRINT_DIRECT 0xE108 115 | #define ID_FILE_PRINT_PREVIEW 0xE109 116 | #define ID_FILE_UPDATE 0xE10A 117 | #define ID_FILE_SAVE_COPY_AS 0xE10B 118 | #define ID_FILE_SEND_MAIL 0xE10C 119 | 120 | #define ID_FILE_MRU_FIRST 0xE110 121 | #define ID_FILE_MRU_FILE1 0xE110 // range - 16 max 122 | #define ID_FILE_MRU_FILE2 0xE111 123 | #define ID_FILE_MRU_FILE3 0xE112 124 | #define ID_FILE_MRU_FILE4 0xE113 125 | #define ID_FILE_MRU_FILE5 0xE114 126 | #define ID_FILE_MRU_FILE6 0xE115 127 | #define ID_FILE_MRU_FILE7 0xE116 128 | #define ID_FILE_MRU_FILE8 0xE117 129 | #define ID_FILE_MRU_FILE9 0xE118 130 | #define ID_FILE_MRU_FILE10 0xE119 131 | #define ID_FILE_MRU_FILE11 0xE11A 132 | #define ID_FILE_MRU_FILE12 0xE11B 133 | #define ID_FILE_MRU_FILE13 0xE11C 134 | #define ID_FILE_MRU_FILE14 0xE11D 135 | #define ID_FILE_MRU_FILE15 0xE11E 136 | #define ID_FILE_MRU_FILE16 0xE11F 137 | #define ID_FILE_MRU_LAST 0xE11F 138 | 139 | // Edit commands 140 | #define ID_EDIT_CLEAR 0xE120 141 | #define ID_EDIT_CLEAR_ALL 0xE121 142 | #define ID_EDIT_COPY 0xE122 143 | #define ID_EDIT_CUT 0xE123 144 | #define ID_EDIT_FIND 0xE124 145 | #define ID_EDIT_PASTE 0xE125 146 | #define ID_EDIT_PASTE_LINK 0xE126 147 | #define ID_EDIT_PASTE_SPECIAL 0xE127 148 | #define ID_EDIT_REPEAT 0xE128 149 | #define ID_EDIT_REPLACE 0xE129 150 | #define ID_EDIT_SELECT_ALL 0xE12A 151 | #define ID_EDIT_UNDO 0xE12B 152 | #define ID_EDIT_REDO 0xE12C 153 | 154 | // Window commands 155 | #define ID_WINDOW_NEW 0xE130 156 | #define ID_WINDOW_ARRANGE 0xE131 157 | #define ID_WINDOW_CASCADE 0xE132 158 | #define ID_WINDOW_TILE_HORZ 0xE133 159 | #define ID_WINDOW_TILE_VERT 0xE134 160 | #define ID_WINDOW_SPLIT 0xE135 161 | #ifndef RC_INVOKED // code only 162 | #define ATL_IDM_WINDOW_FIRST 0xE130 163 | #define ATL_IDM_WINDOW_LAST 0xE13F 164 | #define ATL_IDM_FIRST_MDICHILD 0xFF00 // window list starts here 165 | #define ATL_IDM_LAST_MDICHILD 0xFFFD 166 | #endif // !RC_INVOKED 167 | // TabView 168 | #define ID_WINDOW_TABFIRST 0xFF00 // = ATL_IDM_FIRST_MDICHILD 169 | #define ID_WINDOW_TABLAST 0xFFFD 170 | #define ID_WINDOW_SHOWTABLIST 0xFFFE 171 | 172 | // Help and App commands 173 | #define ID_APP_ABOUT 0xE140 174 | #define ID_APP_EXIT 0xE141 175 | #define ID_HELP_INDEX 0xE142 176 | #define ID_HELP_FINDER 0xE143 177 | #define ID_HELP_USING 0xE144 178 | #define ID_CONTEXT_HELP 0xE145 // shift-F1 179 | // special commands for processing help 180 | #define ID_HELP 0xE146 // first attempt for F1 181 | #define ID_DEFAULT_HELP 0xE147 // last attempt 182 | 183 | // Misc 184 | #define ID_NEXT_PANE 0xE150 185 | #define ID_PREV_PANE 0xE151 186 | #define ID_PANE_CLOSE 0xE152 187 | 188 | // Format 189 | #define ID_FORMAT_FONT 0xE160 190 | 191 | // Scroll 192 | #define ID_SCROLL_UP 0xE170 193 | #define ID_SCROLL_DOWN 0xE171 194 | #define ID_SCROLL_PAGE_UP 0xE172 195 | #define ID_SCROLL_PAGE_DOWN 0xE173 196 | #define ID_SCROLL_TOP 0xE174 197 | #define ID_SCROLL_BOTTOM 0xE175 198 | #define ID_SCROLL_LEFT 0xE176 199 | #define ID_SCROLL_RIGHT 0xE177 200 | #define ID_SCROLL_PAGE_LEFT 0xE178 201 | #define ID_SCROLL_PAGE_RIGHT 0xE179 202 | #define ID_SCROLL_ALL_LEFT 0xE17A 203 | #define ID_SCROLL_ALL_RIGHT 0xE17B 204 | 205 | // OLE commands 206 | #define ID_OLE_INSERT_NEW 0xE200 207 | #define ID_OLE_EDIT_LINKS 0xE201 208 | #define ID_OLE_EDIT_CONVERT 0xE202 209 | #define ID_OLE_EDIT_CHANGE_ICON 0xE203 210 | #define ID_OLE_EDIT_PROPERTIES 0xE204 211 | #define ID_OLE_VERB_FIRST 0xE210 // range - 16 max 212 | #ifndef RC_INVOKED // code only 213 | #define ID_OLE_VERB_LAST 0xE21F 214 | #endif // !RC_INVOKED 215 | 216 | // View commands (same number used as IDW used for toolbar and status bar) 217 | #define ID_VIEW_TOOLBAR 0xE800 218 | #define ID_VIEW_STATUS_BAR 0xE801 219 | #define ID_VIEW_REFRESH 0xE803 220 | #define ID_VIEW_RIBBON 0xE804 // Ribbon 221 | 222 | /////////////////////////////////////////////////////////////////////////////// 223 | // Standard control IDs 224 | 225 | #ifdef IDC_STATIC 226 | #undef IDC_STATIC 227 | #endif // IDC_STATIC 228 | #define IDC_STATIC (-1) // all static controls 229 | 230 | /////////////////////////////////////////////////////////////////////////////// 231 | // Standard string error/warnings 232 | 233 | // idle status bar message 234 | #define ATL_IDS_IDLEMESSAGE 0xE001 235 | 236 | #ifndef RC_INVOKED // code only 237 | #define ATL_IDS_SCFIRST 0xEF00 238 | #endif // !RC_INVOKED 239 | 240 | #define ATL_IDS_SCSIZE 0xEF00 241 | #define ATL_IDS_SCMOVE 0xEF01 242 | #define ATL_IDS_SCMINIMIZE 0xEF02 243 | #define ATL_IDS_SCMAXIMIZE 0xEF03 244 | #define ATL_IDS_SCNEXTWINDOW 0xEF04 245 | #define ATL_IDS_SCPREVWINDOW 0xEF05 246 | #define ATL_IDS_SCCLOSE 0xEF06 247 | #define ATL_IDS_SCRESTORE 0xEF12 248 | #define ATL_IDS_SCTASKLIST 0xEF13 249 | 250 | #define ATL_IDS_MDICHILD 0xEF1F 251 | #define ATL_IDS_MRU_FILE 0xEFDA 252 | 253 | /////////////////////////////////////////////////////////////////////////////// 254 | // Misc. control IDs 255 | 256 | // Property Sheet control id's (determined with Spy++) 257 | #define ID_APPLY_NOW 0x3021 258 | #define ID_WIZBACK 0x3023 259 | #define ID_WIZNEXT 0x3024 260 | #define ID_WIZFINISH 0x3025 261 | #define ATL_IDC_TAB_CONTROL 0x3020 262 | 263 | #endif // __ATLRES_H__ 264 | -------------------------------------------------------------------------------- /D/D/wtl/atldwm.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLDWM_H__ 13 | #define __ATLDWM_H__ 14 | 15 | #pragma once 16 | 17 | #ifdef _WIN32_WCE 18 | #error atldwm.h is not supported on Windows CE 19 | #endif 20 | 21 | #ifndef __ATLAPP_H__ 22 | #error atldwm.h requires atlapp.h to be included first 23 | #endif 24 | 25 | #ifndef __ATLWIN_H__ 26 | #error atldwm.h requires atlwin.h to be included first 27 | #endif 28 | 29 | #if (_WIN32_WINNT < 0x0600) 30 | #error atldwm.h requires _WIN32_WINNT >= 0x0600 31 | #endif // (_WIN32_WINNT < 0x0600) 32 | 33 | #ifndef _DWMAPI_H_ 34 | #include 35 | #endif // _DWMAPI_H_ 36 | #pragma comment(lib, "dwmapi.lib") 37 | 38 | // Note: To create an application that also runs on older versions of Windows, 39 | // use delay load of dwmapi.dll and ensure that no calls to the DWM API are 40 | // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, 41 | // and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the 42 | // project properties. 43 | #if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) 44 | #pragma comment(lib, "delayimp.lib") 45 | #pragma comment(linker, "/delayload:dwmapi.dll") 46 | #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) 47 | 48 | /////////////////////////////////////////////////////////////////////////////// 49 | // Classes in this file: 50 | // 51 | // CDwm 52 | // CDwmImpl 53 | // CDwmWindowT - CDwmWindow 54 | // CDwmThumbnailT 55 | // CDwmThumbnail 56 | // CDwmThumbnailHandle 57 | // CAeroControlImpl 58 | 59 | 60 | namespace WTL 61 | { 62 | 63 | /////////////////////////////////////////////////////////////////////////////// 64 | // CDwm - wrapper for DWM handle 65 | 66 | class CDwm 67 | { 68 | public: 69 | // Data members 70 | static int m_nIsDwmSupported; 71 | 72 | // Constructor 73 | CDwm() 74 | { 75 | IsDwmSupported(); 76 | } 77 | 78 | // Dwm support helper 79 | static bool IsDwmSupported() 80 | { 81 | if(m_nIsDwmSupported == -1) 82 | { 83 | CStaticDataInitCriticalSectionLock lock; 84 | if(FAILED(lock.Lock())) 85 | { 86 | ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\n")); 87 | ATLASSERT(FALSE); 88 | return false; 89 | } 90 | 91 | if(m_nIsDwmSupported == -1) 92 | { 93 | HMODULE hDwmDLL = ::LoadLibrary(_T("dwmapi.dll")); 94 | m_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0; 95 | if(hDwmDLL != NULL) 96 | ::FreeLibrary(hDwmDLL); 97 | } 98 | 99 | lock.Unlock(); 100 | } 101 | 102 | ATLASSERT(m_nIsDwmSupported != -1); 103 | return (m_nIsDwmSupported == 1); 104 | } 105 | 106 | // Operations 107 | BOOL DwmIsCompositionEnabled() const 108 | { 109 | if(!IsDwmSupported()) return FALSE; 110 | BOOL bRes = FALSE; 111 | return SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes; 112 | } 113 | 114 | BOOL DwmEnableComposition(UINT fEnable) 115 | { 116 | if(!IsDwmSupported()) return FALSE; 117 | return SUCCEEDED(::DwmEnableComposition(fEnable)); 118 | } 119 | 120 | BOOL DwmEnableMMCSS(BOOL fEnableMMCSS) 121 | { 122 | if(!IsDwmSupported()) return FALSE; 123 | return SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS)); 124 | } 125 | 126 | HRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend) 127 | { 128 | if(!IsDwmSupported()) return E_NOTIMPL; 129 | return ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend); 130 | } 131 | 132 | HRESULT DwmFlush() 133 | { 134 | if(!IsDwmSupported()) return E_NOTIMPL; 135 | return ::DwmFlush(); 136 | } 137 | }; 138 | 139 | __declspec(selectany) int CDwm::m_nIsDwmSupported = -1; 140 | 141 | 142 | /////////////////////////////////////////////////////////////////////////////// 143 | // CDwmImpl - DWM window support 144 | 145 | template 146 | class CDwmImpl : public TBase 147 | { 148 | public: 149 | HRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB) 150 | { 151 | if(!IsDwmSupported()) return E_NOTIMPL; 152 | T* pT = static_cast(this); 153 | ATLASSERT(::IsWindow(pT->m_hWnd)); 154 | return ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB); 155 | } 156 | 157 | HRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins) 158 | { 159 | if(!IsDwmSupported()) return E_NOTIMPL; 160 | T* pT = static_cast(this); 161 | ATLASSERT(::IsWindow(pT->m_hWnd)); 162 | return ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins); 163 | } 164 | 165 | HRESULT DwmExtendFrameIntoEntireClientArea() 166 | { 167 | MARGINS margins = { -1 }; 168 | return DwmExtendFrameIntoClientArea(&margins); 169 | } 170 | 171 | HRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo) 172 | { 173 | if(!IsDwmSupported()) return E_NOTIMPL; 174 | T* pT = static_cast(this); 175 | ATLASSERT(::IsWindow(pT->m_hWnd)); 176 | return ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo); 177 | } 178 | 179 | HRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute) 180 | { 181 | if(!IsDwmSupported()) return E_NOTIMPL; 182 | T* pT = static_cast(this); 183 | ATLASSERT(::IsWindow(pT->m_hWnd)); 184 | return ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); 185 | } 186 | 187 | HRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative) 188 | { 189 | if(!IsDwmSupported()) return E_NOTIMPL; 190 | T* pT = static_cast(this); 191 | ATLASSERT(::IsWindow(pT->m_hWnd)); 192 | return ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative); 193 | } 194 | 195 | HRESULT DwmSetDxFrameDuration(INT cRefreshes) 196 | { 197 | if(!IsDwmSupported()) return E_NOTIMPL; 198 | T* pT = static_cast(this); 199 | ATLASSERT(::IsWindow(pT->m_hWnd)); 200 | return ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes); 201 | } 202 | 203 | HRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams) 204 | { 205 | if(!IsDwmSupported()) return E_NOTIMPL; 206 | T* pT = static_cast(this); 207 | ATLASSERT(::IsWindow(pT->m_hWnd)); 208 | return ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams); 209 | } 210 | 211 | HRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) 212 | { 213 | if(!IsDwmSupported()) return E_NOTIMPL; 214 | T* pT = static_cast(this); 215 | ATLASSERT(::IsWindow(pT->m_hWnd)); 216 | return ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); 217 | } 218 | 219 | HRESULT DwmAttachMilContent() 220 | { 221 | if(!IsDwmSupported()) return E_NOTIMPL; 222 | T* pT = static_cast(this); 223 | ATLASSERT(::IsWindow(pT->m_hWnd)); 224 | return ::DwmAttachMilContent(pT->m_hWnd); 225 | } 226 | 227 | HRESULT DwmDetachMilContent() 228 | { 229 | if(!IsDwmSupported()) return E_NOTIMPL; 230 | T* pT = static_cast(this); 231 | ATLASSERT(::IsWindow(pT->m_hWnd)); 232 | return ::DwmDetachMilContent(pT->m_hWnd); 233 | } 234 | }; 235 | 236 | template 237 | class CDwmWindowT : public TBase, public CDwmImpl > 238 | { 239 | public: 240 | CDwmWindowT(HWND hWnd = NULL) : TBase(hWnd) 241 | { } 242 | 243 | CDwmWindowT< TBase >& operator =(HWND hWnd) 244 | { 245 | m_hWnd = hWnd; 246 | return *this; 247 | } 248 | }; 249 | 250 | typedef CDwmWindowT CDwmWindow; 251 | 252 | 253 | /////////////////////////////////////////////////////////////////////////////// 254 | // CDwmThumbnail - provides DWM thumbnail support 255 | 256 | template 257 | class CDwmThumbnailT : public TBase 258 | { 259 | public: 260 | // Data members 261 | HTHUMBNAIL m_hThumbnail; 262 | 263 | // Constructor 264 | CDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail) 265 | { 266 | } 267 | 268 | ~CDwmThumbnailT() 269 | { 270 | if(t_bManaged && m_hThumbnail != NULL) 271 | Unregister(); 272 | } 273 | 274 | // Operations 275 | CDwmThumbnailT& operator =(HTHUMBNAIL hThumbnail) 276 | { 277 | Attach(hThumbnail); 278 | return *this; 279 | } 280 | 281 | void Attach(HTHUMBNAIL hThumbnailNew) 282 | { 283 | if(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew) 284 | Unregister(); 285 | m_hThumbnail = hThumbnailNew; 286 | } 287 | 288 | HTHUMBNAIL Detach() 289 | { 290 | HTHUMBNAIL hThumbnail = m_hThumbnail; 291 | m_hThumbnail = NULL; 292 | return hThumbnail; 293 | } 294 | 295 | HRESULT Register(HWND hwndDestination, HWND hwndSource) 296 | { 297 | ATLASSERT(::IsWindow(hwndDestination)); 298 | ATLASSERT(::IsWindow(hwndSource)); 299 | ATLASSERT(m_hThumbnail==NULL); 300 | if(!IsDwmSupported()) return E_NOTIMPL; 301 | return ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail); 302 | } 303 | 304 | HRESULT Unregister() 305 | { 306 | if(!IsDwmSupported()) return E_NOTIMPL; 307 | if(m_hThumbnail == NULL) return S_FALSE; 308 | HRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail); 309 | if(SUCCEEDED(Hr)) m_hThumbnail = NULL; 310 | return Hr; 311 | } 312 | 313 | operator HTHUMBNAIL() const { return m_hThumbnail; } 314 | 315 | bool IsNull() const { return (m_hThumbnail == NULL); } 316 | 317 | HRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties) 318 | { 319 | if(!IsDwmSupported()) return E_NOTIMPL; 320 | ATLASSERT(m_hThumbnail != NULL); 321 | return ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties); 322 | } 323 | 324 | // Attributes 325 | HRESULT QuerySourceSize(PSIZE pSize) 326 | { 327 | if(!IsDwmSupported()) return E_NOTIMPL; 328 | ATLASSERT(m_hThumbnail != NULL); 329 | return ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize); 330 | } 331 | }; 332 | 333 | typedef CDwmThumbnailT CDwmThumbnail; 334 | typedef CDwmThumbnailT CDwmThumbnailHandle; 335 | 336 | 337 | #ifdef __ATLTHEME_H__ 338 | 339 | /////////////////////////////////////////////////////////////////////////////// 340 | // CAeroControlImpl - Base class for controls on Glass 341 | 342 | template 343 | class CAeroControlImpl : 344 | public CThemeImpl, 345 | public CBufferedPaintImpl, 346 | public ATL::CWindowImpl 347 | { 348 | public: 349 | typedef CThemeImpl _themeClass; 350 | typedef CBufferedPaintImpl _baseClass; 351 | typedef ATL::CWindowImpl _windowClass; 352 | 353 | CAeroControlImpl() 354 | { 355 | m_PaintParams.dwFlags = BPPF_ERASE; 356 | } 357 | 358 | static LPCWSTR GetThemeName() 359 | { 360 | #ifdef _UNICODE 361 | return TBase::GetWndClassName(); 362 | #else 363 | ATLASSERT(!_T("Return UNICODE string of window classname / theme class")); 364 | return NULL; 365 | #endif // _UNICODE 366 | } 367 | 368 | // Message map and handlers 369 | BEGIN_MSG_MAP(CAeroControlImpl) 370 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 371 | MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) 372 | CHAIN_MSG_MAP(_themeClass) 373 | CHAIN_MSG_MAP(_baseClass) 374 | END_MSG_MAP() 375 | 376 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 377 | { 378 | T* pT = static_cast(this); 379 | pT->Init(); 380 | bHandled = FALSE; 381 | return 0; 382 | } 383 | 384 | LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 385 | { 386 | if(IsThemingSupported()) Invalidate(FALSE); 387 | bHandled = FALSE; 388 | return 0; 389 | } 390 | 391 | // Operations 392 | BOOL SubclassWindow(HWND hWnd) 393 | { 394 | ATLASSERT(m_hWnd == NULL); 395 | ATLASSERT(::IsWindow(hWnd)); 396 | BOOL bRet = _windowClass::SubclassWindow(hWnd); 397 | if(bRet) { 398 | T* pT = static_cast(this); 399 | pT->Init(); 400 | } 401 | return bRet; 402 | } 403 | 404 | // Implementation 405 | LRESULT DefWindowProc() 406 | { 407 | const _ATL_MSG* pMsg = m_pCurrentMsg; 408 | LRESULT lRes = 0; 409 | if(pMsg != NULL) 410 | lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); 411 | return lRes; 412 | } 413 | 414 | LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) 415 | { 416 | T* pT = static_cast(this); 417 | LRESULT lRes = 0; 418 | if( ::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) ) return lRes; 419 | return _windowClass::DefWindowProc(uMsg, wParam, lParam); 420 | } 421 | 422 | void DoBufferedPaint(HDC hDC, RECT& rcPaint) 423 | { 424 | T* pT = static_cast(this); 425 | HDC hDCPaint = NULL; 426 | RECT rcClient = { 0 }; 427 | GetClientRect(&rcClient); 428 | m_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint); 429 | ATLASSERT(hDCPaint != NULL); 430 | pT->DoAeroPaint(hDCPaint, rcClient, rcPaint); 431 | m_BufferedPaint.End(); 432 | } 433 | 434 | void DoPaint(HDC /*hdc*/, RECT& /*rcClient*/) 435 | { 436 | DefWindowProc(); 437 | } 438 | 439 | // Overridables 440 | void Init() 441 | { 442 | T* pT = static_cast(this); 443 | SetThemeClassList(pT->GetThemeName()); 444 | if(m_lpstrThemeClassList != NULL) 445 | OpenThemeData(); 446 | } 447 | 448 | void DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint) 449 | { 450 | DefWindowProc(WM_PAINT, (WPARAM) hDC, 0L); 451 | m_BufferedPaint.MakeOpaque(&rcPaint); 452 | } 453 | }; 454 | 455 | #endif // __ATLTHEME_H__ 456 | 457 | 458 | }; // namespace WTL 459 | 460 | 461 | #endif // __ATLDWM_H__ 462 | -------------------------------------------------------------------------------- /D/D/D.cpp: -------------------------------------------------------------------------------- 1 | // D.cpp : 定义应用程序的入口点。 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "D.h" 6 | 7 | #define MAX_LOADSTRING 100 8 | 9 | ID2D1Factory *gD2dFactory = nullptr; 10 | IWICImagingFactory *gWICFactory = nullptr; 11 | IWICBitmap *gWicBitmap = nullptr; 12 | ID2D1RenderTarget *FRt = nullptr; 13 | ID2D1GdiInteropRenderTarget *FInteropTarget = nullptr; 14 | ID2D1RadialGradientBrush * FBrush = nullptr; 15 | POINT FSourcePosition; 16 | POINT FWindowPosition; 17 | SIZE FSize; 18 | BLENDFUNCTION FBlend; 19 | int Width = 600; 20 | int Height = 600; 21 | ID2D1DCRenderTarget *dcRenderTarget = nullptr; 22 | ID2D1HwndRenderTarget *hwndRenderTarget = nullptr; 23 | ID2D1HwndRenderTarget *hwndRenderTarget1 = nullptr; 24 | ID2D1Bitmap *gBitmap = nullptr; 25 | ID2D1SolidColorBrush *gBrush = nullptr; 26 | HDC gDC = nullptr; 27 | // 全局变量: 28 | HINSTANCE hInst; // 当前实例 29 | TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 30 | TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 31 | 32 | CDCHandle hDcOffScreen = NULL; 33 | CBitmap hBmpOffScreen = NULL; 34 | LPVOID pBmpOffScreenBits = NULL; 35 | // 窗体信息 36 | int nClientWidth = 0; 37 | int nClientHeight = 0; 38 | 39 | // 此代码模块中包含的函数的前向声明: 40 | ATOM MyRegisterClass(HINSTANCE hInstance); 41 | BOOL InitInstance(HINSTANCE, int); 42 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 43 | INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 44 | ULONG_PTR gdiplusStartupToken; 45 | int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, 46 | _In_opt_ HINSTANCE hPrevInstance, 47 | _In_ LPTSTR lpCmdLine, 48 | _In_ int nCmdShow) 49 | { 50 | UNREFERENCED_PARAMETER(hPrevInstance); 51 | UNREFERENCED_PARAMETER(lpCmdLine); 52 | Gdiplus::GdiplusStartupInput gdiInput; 53 | Gdiplus::GdiplusStartup(&gdiplusStartupToken, &gdiInput, NULL); 54 | CoInitialize(nullptr); 55 | // TODO: 在此放置代码。 56 | MSG msg; 57 | HACCEL hAccelTable; 58 | 59 | // 初始化全局字符串 60 | LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 61 | LoadString(hInstance, IDC_D, szWindowClass, MAX_LOADSTRING); 62 | MyRegisterClass(hInstance); 63 | 64 | HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &gD2dFactory); 65 | if (FAILED(hr)) 66 | { 67 | MessageBox(nullptr, L"Create D2D factory failed£¡", L"Ìáʾ", MB_OK); 68 | return 0; 69 | } 70 | 71 | hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, 72 | IID_IWICImagingFactory, (LPVOID*)&gWICFactory); 73 | if (FAILED(hr)) 74 | { 75 | MessageBox(nullptr, L"Create WIC factory failed£¡", L"Ìáʾ", MB_OK); 76 | return 0; 77 | } 78 | 79 | // 执行应用程序初始化: 80 | if (!InitInstance (hInstance, nCmdShow)) 81 | { 82 | return FALSE; 83 | } 84 | 85 | hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D)); 86 | 87 | // 主消息循环: 88 | while (GetMessage(&msg, NULL, 0, 0)) 89 | { 90 | if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 91 | { 92 | TranslateMessage(&msg); 93 | DispatchMessage(&msg); 94 | } 95 | } 96 | 97 | CoUninitialize(); 98 | Gdiplus::GdiplusShutdown(gdiplusStartupToken); 99 | return (int) msg.wParam; 100 | } 101 | 102 | HBITMAP CreateGDIBitmap(int nWid, int nHei, void ** ppBits) 103 | { 104 | BITMAPINFO bmi; 105 | memset(&bmi, 0, sizeof(bmi)); 106 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 107 | bmi.bmiHeader.biWidth = nWid; 108 | bmi.bmiHeader.biHeight = -nHei; // top-down image 109 | bmi.bmiHeader.biPlanes = 1; 110 | bmi.bmiHeader.biBitCount = 32; 111 | bmi.bmiHeader.biCompression = BI_RGB; 112 | bmi.bmiHeader.biSizeImage = 0; 113 | 114 | HDC hdc = ::GetDC(NULL); 115 | LPVOID pBits = NULL; 116 | HBITMAP hBmp = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, ppBits, 0, 0); 117 | ::ReleaseDC(NULL, hdc); 118 | return hBmp; 119 | } 120 | 121 | HRESULT LoadImageFile(IWICImagingFactory *pIWICFactory, 122 | PCWSTR uri, 123 | UINT destinationWidth, 124 | UINT destinationHeight) 125 | { 126 | HRESULT hRet = S_OK; 127 | 128 | IWICBitmapDecoder *pDecoder = nullptr; 129 | IWICBitmapFrameDecode *pSource = nullptr; 130 | IWICStream *pStream = nullptr; 131 | IWICFormatConverter *pConverter = nullptr; 132 | IWICBitmapScaler *pScaler = nullptr; 133 | 134 | hRet = pIWICFactory->CreateDecoderFromFilename(uri, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder); 135 | if (SUCCEEDED(hRet)) 136 | { 137 | hRet = pDecoder->GetFrame(0, &pSource); 138 | } 139 | 140 | if (SUCCEEDED(hRet)) 141 | { 142 | hRet = pIWICFactory->CreateFormatConverter(&pConverter); 143 | } 144 | 145 | 146 | UINT originalWidth, originalHeight; 147 | hRet = pSource->GetSize(&originalWidth, &originalHeight); 148 | if (SUCCEEDED(hRet)) 149 | { 150 | if (destinationWidth != 0 && destinationHeight != 0) 151 | { 152 | originalWidth = destinationWidth; 153 | originalHeight = destinationHeight; 154 | } 155 | 156 | hRet = pIWICFactory->CreateBitmapScaler(&pScaler); 157 | if (SUCCEEDED(hRet)) 158 | { 159 | hRet = pScaler->Initialize(pSource, originalWidth, originalHeight, WICBitmapInterpolationModeCubic); 160 | } 161 | 162 | if (SUCCEEDED(hRet)) 163 | { 164 | hRet = pConverter->Initialize(pScaler, GUID_WICPixelFormat32bppPBGRA, 165 | WICBitmapDitherTypeNone, 166 | nullptr, 167 | 0.f, 168 | WICBitmapPaletteTypeMedianCut); 169 | } 170 | } 171 | if (SUCCEEDED(hRet)) 172 | { 173 | hRet = dcRenderTarget->CreateBitmapFromWicBitmap(pConverter, nullptr, &gBitmap); 174 | } 175 | 176 | if (SUCCEEDED(hRet)) 177 | { 178 | hRet = pIWICFactory->CreateBitmapFromSource(pConverter, WICBitmapCacheOnLoad, &gWicBitmap); 179 | } 180 | SAFE_RELEASE(pDecoder); 181 | SAFE_RELEASE(pSource); 182 | SAFE_RELEASE(pStream); 183 | SAFE_RELEASE(pConverter); 184 | SAFE_RELEASE(pScaler); 185 | 186 | return hRet; 187 | } 188 | 189 | void CreateDeviceResources(HWND hWnd) 190 | { 191 | FSourcePosition.x = FSourcePosition.y = 0; 192 | FWindowPosition.x = FWindowPosition.y = 0; 193 | FSize.cx = Width; //600; 194 | FSize.cy = Height; //400; 195 | 196 | FBlend.BlendOp = AC_SRC_OVER; 197 | FBlend.BlendFlags = 0; 198 | FBlend.SourceConstantAlpha = 255; 199 | FBlend.AlphaFormat = AC_SRC_ALPHA; 200 | 201 | D2D1_PIXEL_FORMAT pf = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); 202 | D2D1_RENDER_TARGET_PROPERTIES rtp = D2D1::RenderTargetProperties( 203 | D2D1_RENDER_TARGET_TYPE_DEFAULT, 204 | pf, 205 | 0, 206 | 0, 207 | D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE); 208 | 209 | HRESULT hr = gD2dFactory->CreateHwndRenderTarget(rtp, 210 | D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(600, 600)), 211 | &hwndRenderTarget); 212 | 213 | hwndRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)(&FInteropTarget)); 214 | 215 | 216 | 217 | D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( 218 | D2D1_RENDER_TARGET_TYPE_DEFAULT, 219 | D2D1::PixelFormat( 220 | DXGI_FORMAT_B8G8R8A8_UNORM, 221 | D2D1_ALPHA_MODE_PREMULTIPLIED), 222 | 0, 223 | 0, 224 | D2D1_RENDER_TARGET_USAGE_NONE, 225 | D2D1_FEATURE_LEVEL_DEFAULT 226 | ); 227 | 228 | hr = gD2dFactory->CreateDCRenderTarget(&props, &dcRenderTarget); 229 | LoadImageFile(gWICFactory, L"2.png", 68, 68); 230 | dcRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &gBrush); 231 | } 232 | 233 | // 234 | // 函数: MyRegisterClass() 235 | // 236 | // 目的: 注册窗口类。 237 | // 238 | ATOM MyRegisterClass(HINSTANCE hInstance) 239 | { 240 | WNDCLASSEX wcex; 241 | 242 | wcex.cbSize = sizeof(WNDCLASSEX); 243 | 244 | wcex.style = CS_HREDRAW | CS_VREDRAW; 245 | wcex.lpfnWndProc = WndProc; 246 | wcex.cbClsExtra = 0; 247 | wcex.cbWndExtra = 0; 248 | wcex.hInstance = hInstance; 249 | wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D)); 250 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 251 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 252 | wcex.lpszMenuName = nullptr;// AKEINTRESOURCE(IDC_D); 253 | wcex.lpszClassName = szWindowClass; 254 | wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 255 | 256 | return RegisterClassEx(&wcex); 257 | } 258 | 259 | void Render(HWND hwnd) 260 | { 261 | PAINTSTRUCT ps; 262 | RECT rcClient; 263 | GetClientRect(hwnd, &rcClient); 264 | CPaintDC dc(hwnd); 265 | 266 | if ((nClientWidth != rcClient.right - rcClient.left) || 267 | (nClientHeight != rcClient.bottom - rcClient.top) || 268 | hBmpOffScreen.IsNull()|| hDcOffScreen.IsNull()) 269 | { 270 | nClientWidth = rcClient.right - rcClient.left; 271 | nClientHeight = rcClient.bottom - rcClient.top; 272 | 273 | if (!hBmpOffScreen.IsNull()) 274 | hBmpOffScreen.DeleteObject(); 275 | 276 | if (!hDcOffScreen.IsNull()) 277 | hDcOffScreen.DeleteDC(); 278 | hDcOffScreen.CreateCompatibleDC(dc); 279 | HBITMAP hBitmap = CreateGDIBitmap(nClientWidth, nClientHeight, &pBmpOffScreenBits); 280 | hBmpOffScreen.Attach(hBitmap); 281 | 282 | hDcOffScreen.SelectBitmap(hBmpOffScreen); 283 | hDcOffScreen.SetBkMode(TRANSPARENT); 284 | } 285 | 286 | HRESULT hr = dcRenderTarget->BindDC(hDcOffScreen, &rcClient); 287 | dcRenderTarget->BeginDraw(); 288 | dcRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); 289 | D2D1_SIZE_F size = gBitmap->GetSize(); 290 | D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f); 291 | dcRenderTarget->DrawBitmap( 292 | gBitmap, 293 | D2D1::RectF( 294 | (rcClient.left), 295 | (rcClient.top), 296 | (size.width), 297 | (size.height)), 298 | 1.0f); 299 | dcRenderTarget->EndDraw(); 300 | // BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; 301 | // dc.AlphaBlend(0, 0, nClientWidth, nClientWidth 302 | // , hDcOffScreen, 0, 0, nClientWidth, nClientWidth, bf); 303 | 304 | 305 | // 306 | // POINT ptDest = { rcClient.left, rcClient.top }; 307 | // POINT ptSrc = { 0, 0 }; 308 | // SIZE szLayered = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 309 | // BLENDFUNCTION bf; 310 | // bf.AlphaFormat = AC_SRC_ALPHA; 311 | // bf.BlendFlags = 0; 312 | // bf.BlendOp = AC_SRC_OVER; 313 | // bf.SourceConstantAlpha = 255; 314 | // ::UpdateLayeredWindow(hwnd, hDcOffScreen, &ptDest, &szLayered, hdc, &ptSrc, (COLORREF)0, &bf, ULW_ALPHA); 315 | // 316 | 317 | } 318 | 319 | void Render1(HWND hwnd) 320 | { 321 | RECT rc; 322 | ZeroMemory(&rc, sizeof(rc)); 323 | RECT rcClient; 324 | ::GetWindowRect(hwnd, &rcClient); 325 | SIZE wndSize = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 326 | HDC myhdc = NULL; 327 | 328 | hwndRenderTarget->BeginDraw(); 329 | 330 | hwndRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Yellow)); 331 | hwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); 332 | FInteropTarget->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &myhdc); 333 | 334 | gDC = ::CreateCompatibleDC(myhdc); 335 | HBITMAP memBitmap = ::CreateCompatibleBitmap(myhdc, wndSize.cx, wndSize.cy); 336 | ::SelectObject(gDC, memBitmap); 337 | 338 | // 用gdi+来读取图片文件 339 | Gdiplus::Image image(L"bk1.png"); 340 | Gdiplus::Graphics graphics(gDC); 341 | graphics.DrawImage(&image, 0, 0, wndSize.cx, wndSize.cy); 342 | // 343 | // Gdiplus::Image image2(L"2.png"); 344 | // Gdiplus::Graphics graphics2(gDC); 345 | // graphics2.DrawImage(&image2, 0, 0, 68, 68); 346 | 347 | POINT ptDest = { rcClient.left, rcClient.top }; 348 | POINT ptSrc = { 0, 0 }; 349 | SIZE szLayered = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 350 | BLENDFUNCTION bf; 351 | bf.AlphaFormat = AC_SRC_ALPHA; 352 | bf.BlendFlags = 0; 353 | bf.BlendOp = AC_SRC_OVER; 354 | bf.SourceConstantAlpha = 255; 355 | FInteropTarget->ReleaseDC(&rcClient); 356 | hwndRenderTarget->EndDraw(); 357 | ::UpdateLayeredWindow(hwnd, NULL, &ptDest, &szLayered, gDC, &ptSrc, RGB(0, 0, 0), &bf, ULW_ALPHA); 358 | } 359 | 360 | void Render2(HWND hwnd) 361 | { 362 | RECT rc; 363 | ZeroMemory(&rc, sizeof(rc)); 364 | RECT rcClient; 365 | ::GetWindowRect(hwnd, &rcClient); 366 | SIZE wndSize = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 367 | HDC hwndDC = GetDC(hwnd); 368 | 369 | gDC = ::CreateCompatibleDC(hwndDC); 370 | HBITMAP memBitmap = ::CreateCompatibleBitmap(hwndDC, wndSize.cx, wndSize.cy); 371 | ::SelectObject(gDC, memBitmap); 372 | dcRenderTarget->BindDC(gDC, &rcClient); 373 | dcRenderTarget->BeginDraw(); 374 | dcRenderTarget->DrawLine(D2D1::Point2F(200, 200), D2D1::Point2F(300, 300), gBrush, 50); 375 | dcRenderTarget->DrawLine(D2D1::Point2F(100, 100), D2D1::Point2F(100, 300), gBrush, 50); 376 | dcRenderTarget->DrawLine(D2D1::Point2F(0, 0), D2D1::Point2F(100, 600), gBrush); 377 | dcRenderTarget->DrawBitmap(gBitmap, D2D1::RectF(0, 0, 68, 68), 1.0f); 378 | dcRenderTarget->EndDraw(); 379 | POINT ptDest = { rcClient.left, rcClient.top }; 380 | POINT ptSrc = { 0, 0 }; 381 | SIZE szLayered = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 382 | BLENDFUNCTION bf; 383 | bf.AlphaFormat = AC_SRC_ALPHA; 384 | bf.BlendFlags = 0; 385 | bf.BlendOp = AC_SRC_OVER; 386 | bf.SourceConstantAlpha = 255; 387 | ::UpdateLayeredWindow(hwnd, hwndDC, &ptDest, &szLayered, gDC, &ptSrc, RGB(0, 0, 0), &bf, ULW_ALPHA); 388 | ::ReleaseDC(nullptr, gDC); 389 | ::ReleaseDC(hwnd, hwndDC); 390 | } 391 | // 392 | // 函数: InitInstance(HINSTANCE, int) 393 | // 394 | // 目的: 保存实例句柄并创建主窗口 395 | // 396 | // 注释: 397 | // 398 | // 在此函数中,我们在全局变量中保存实例句柄并 399 | // 创建和显示主程序窗口。 400 | // 401 | BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 402 | { 403 | HWND hWnd; 404 | 405 | hInst = hInstance; // 将实例句柄存储在全局变量中 406 | 407 | hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 408 | 200, 100, Width, Height, NULL, NULL, hInstance, NULL); 409 | 410 | if (!hWnd) 411 | { 412 | return FALSE; 413 | } 414 | 415 | CreateDeviceResources(hWnd); 416 | SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); 417 | 418 | ShowWindow(hWnd, nCmdShow); 419 | UpdateWindow(hWnd); 420 | // 421 | RECT rc; 422 | GetClientRect(hWnd, &rc); 423 | ::InvalidateRect(hWnd, &rc, FALSE); 424 | return TRUE; 425 | } 426 | 427 | // 428 | // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) 429 | // 430 | // 目的: 处理主窗口的消息。 431 | // 432 | // WM_COMMAND - 处理应用程序菜单 433 | // WM_PAINT - 绘制主窗口 434 | // WM_DESTROY - 发送退出消息并返回 435 | // 436 | // 437 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 438 | { 439 | int wmId, wmEvent; 440 | PAINTSTRUCT ps; 441 | RECT rc; 442 | HDC hdc; 443 | ZeroMemory(&rc, sizeof(rc)); 444 | switch (message) 445 | { 446 | case WM_COMMAND: 447 | wmId = LOWORD(wParam); 448 | wmEvent = HIWORD(wParam); 449 | // 分析菜单选择: 450 | switch (wmId) 451 | { 452 | case IDM_ABOUT: 453 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 454 | break; 455 | case IDM_EXIT: 456 | DestroyWindow(hWnd); 457 | break; 458 | default: 459 | return DefWindowProc(hWnd, message, wParam, lParam); 460 | } 461 | break; 462 | case WM_SIZE: 463 | if (hwndRenderTarget) 464 | { 465 | RECT rc; 466 | GetClientRect(hWnd, &rc); 467 | hwndRenderTarget->Resize(D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)); 468 | } 469 | break; 470 | case WM_ERASEBKGND: 471 | return 0; 472 | case WM_LBUTTONDOWN: 473 | //SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, true, nullptr, 0); 474 | SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); 475 | break; 476 | // case WM_MOUSEMOVE: 477 | // //SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, false, nullptr, 0); 478 | // break; 479 | case WM_PAINT: 480 | { 481 | //Render(hWnd); 482 | //Render1(hWnd); 483 | Render2(hWnd); 484 | } 485 | break; 486 | case WM_DESTROY: 487 | PostQuitMessage(0); 488 | break; 489 | default: 490 | return DefWindowProc(hWnd, message, wParam, lParam); 491 | } 492 | return 0; 493 | } 494 | 495 | // “关于”框的消息处理程序。 496 | INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 497 | { 498 | UNREFERENCED_PARAMETER(lParam); 499 | switch (message) 500 | { 501 | case WM_INITDIALOG: 502 | return (INT_PTR)TRUE; 503 | 504 | case WM_COMMAND: 505 | if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 506 | { 507 | EndDialog(hDlg, LOWORD(wParam)); 508 | return (INT_PTR)TRUE; 509 | } 510 | break; 511 | } 512 | return (INT_PTR)FALSE; 513 | } 514 | -------------------------------------------------------------------------------- /D/D/wtl/atlwinx.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLWINX_H__ 13 | #define __ATLWINX_H__ 14 | 15 | #pragma once 16 | 17 | #ifndef __ATLAPP_H__ 18 | #error atlwinx.h requires atlapp.h to be included first 19 | #endif 20 | 21 | #if (_ATL_VER >= 0x0700) 22 | #include 23 | #endif // (_ATL_VER >= 0x0700) 24 | 25 | 26 | /////////////////////////////////////////////////////////////////////////////// 27 | // Classes in this file: 28 | // 29 | // _U_RECT 30 | // _U_MENUorID 31 | // _U_STRINGorID 32 | 33 | 34 | /////////////////////////////////////////////////////////////////////////////// 35 | // Command Chaining Macros 36 | 37 | #define CHAIN_COMMANDS(theChainClass) \ 38 | if(uMsg == WM_COMMAND) \ 39 | CHAIN_MSG_MAP(theChainClass) 40 | 41 | #define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ 42 | if(uMsg == WM_COMMAND) \ 43 | CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) 44 | 45 | #define CHAIN_COMMANDS_MEMBER(theChainMember) \ 46 | if(uMsg == WM_COMMAND) \ 47 | CHAIN_MSG_MAP_MEMBER(theChainMember) 48 | 49 | #define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ 50 | if(uMsg == WM_COMMAND) \ 51 | CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) 52 | 53 | 54 | /////////////////////////////////////////////////////////////////////////////// 55 | // Macros for parent message map to selectively reflect control messages 56 | 57 | // NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot 58 | // (and overridden in 2 cases - CContainedWindowT and CAxHostWindow) 59 | // Since we can't modify ATL, we'll provide the needed additions 60 | // in a separate function (that is not a member of CWindowImplRoot) 61 | 62 | namespace WTL 63 | { 64 | 65 | inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled, 66 | UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL) 67 | { 68 | if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg)) 69 | { 70 | // The notification message doesn't match the filter. 71 | bHandled = FALSE; 72 | return 1; 73 | } 74 | 75 | HWND hWndChild = NULL; 76 | UINT_PTR idFrom = 0; 77 | 78 | switch(uMsg) 79 | { 80 | case WM_COMMAND: 81 | if(lParam != NULL) // not from a menu 82 | { 83 | hWndChild = (HWND)lParam; 84 | idFrom = (UINT_PTR)LOWORD(wParam); 85 | } 86 | break; 87 | case WM_NOTIFY: 88 | hWndChild = ((LPNMHDR)lParam)->hwndFrom; 89 | idFrom = ((LPNMHDR)lParam)->idFrom; 90 | break; 91 | #ifndef _WIN32_WCE 92 | case WM_PARENTNOTIFY: 93 | switch(LOWORD(wParam)) 94 | { 95 | case WM_CREATE: 96 | case WM_DESTROY: 97 | hWndChild = (HWND)lParam; 98 | idFrom = (UINT_PTR)HIWORD(wParam); 99 | break; 100 | default: 101 | hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam)); 102 | idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); 103 | break; 104 | } 105 | break; 106 | #endif // !_WIN32_WCE 107 | case WM_DRAWITEM: 108 | if(wParam) // not from a menu 109 | { 110 | hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem; 111 | idFrom = (UINT_PTR)wParam; 112 | } 113 | break; 114 | case WM_MEASUREITEM: 115 | if(wParam) // not from a menu 116 | { 117 | hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID); 118 | idFrom = (UINT_PTR)wParam; 119 | } 120 | break; 121 | case WM_COMPAREITEM: 122 | if(wParam) // not from a menu 123 | { 124 | hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem; 125 | idFrom = (UINT_PTR)wParam; 126 | } 127 | break; 128 | case WM_DELETEITEM: 129 | if(wParam) // not from a menu 130 | { 131 | hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem; 132 | idFrom = (UINT_PTR)wParam; 133 | } 134 | break; 135 | case WM_VKEYTOITEM: 136 | case WM_CHARTOITEM: 137 | case WM_HSCROLL: 138 | case WM_VSCROLL: 139 | hWndChild = (HWND)lParam; 140 | idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); 141 | break; 142 | case WM_CTLCOLORBTN: 143 | case WM_CTLCOLORDLG: 144 | case WM_CTLCOLOREDIT: 145 | case WM_CTLCOLORLISTBOX: 146 | case WM_CTLCOLORMSGBOX: 147 | case WM_CTLCOLORSCROLLBAR: 148 | case WM_CTLCOLORSTATIC: 149 | hWndChild = (HWND)lParam; 150 | idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); 151 | break; 152 | default: 153 | break; 154 | } 155 | 156 | if((hWndChild == NULL) || 157 | ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild))) 158 | { 159 | // Either hWndChild isn't valid, or 160 | // hWndChild doesn't match the filter. 161 | bHandled = FALSE; 162 | return 1; 163 | } 164 | 165 | if((idFromFilter != 0) && (idFromFilter != idFrom)) 166 | { 167 | // The dialog control id doesn't match the filter. 168 | bHandled = FALSE; 169 | return 1; 170 | } 171 | 172 | ATLASSERT(::IsWindow(hWndChild)); 173 | LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam); 174 | if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) 175 | { 176 | // Try to prevent problems with WM_CTLCOLOR* messages when 177 | // the message wasn't really handled 178 | bHandled = FALSE; 179 | } 180 | 181 | return lResult; 182 | } 183 | 184 | }; // namespace WTL 185 | 186 | // Try to prevent problems with WM_CTLCOLOR* messages when 187 | // the message wasn't really handled 188 | #define REFLECT_NOTIFICATIONS_EX() \ 189 | { \ 190 | bHandled = TRUE; \ 191 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 192 | if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \ 193 | bHandled = FALSE; \ 194 | if(bHandled) \ 195 | return TRUE; \ 196 | } 197 | 198 | #define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \ 199 | { \ 200 | bHandled = TRUE; \ 201 | lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \ 202 | if(bHandled) \ 203 | return TRUE; \ 204 | } 205 | 206 | #define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \ 207 | { \ 208 | bHandled = TRUE; \ 209 | lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \ 210 | if(bHandled) \ 211 | return TRUE; \ 212 | } 213 | 214 | #define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \ 215 | { \ 216 | bHandled = TRUE; \ 217 | lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \ 218 | if(bHandled) \ 219 | return TRUE; \ 220 | } 221 | 222 | #define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \ 223 | { \ 224 | bHandled = TRUE; \ 225 | lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \ 226 | if(bHandled) \ 227 | return TRUE; \ 228 | } 229 | 230 | #define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \ 231 | { \ 232 | bHandled = TRUE; \ 233 | lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \ 234 | if(bHandled) \ 235 | return TRUE; \ 236 | } 237 | 238 | #define REFLECT_COMMAND(id, code) \ 239 | if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ 240 | { \ 241 | bHandled = TRUE; \ 242 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 243 | if(bHandled) \ 244 | return TRUE; \ 245 | } 246 | 247 | #define REFLECT_COMMAND_ID(id) \ 248 | if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ 249 | { \ 250 | bHandled = TRUE; \ 251 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 252 | if(bHandled) \ 253 | return TRUE; \ 254 | } 255 | 256 | #define REFLECT_COMMAND_CODE(code) \ 257 | if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \ 258 | { \ 259 | bHandled = TRUE; \ 260 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 261 | if(bHandled) \ 262 | return TRUE; \ 263 | } 264 | 265 | #define REFLECT_COMMAND_RANGE(idFirst, idLast) \ 266 | if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ 267 | { \ 268 | bHandled = TRUE; \ 269 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 270 | if(bHandled) \ 271 | return TRUE; \ 272 | } 273 | 274 | #define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \ 275 | if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ 276 | { \ 277 | bHandled = TRUE; \ 278 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 279 | if(bHandled) \ 280 | return TRUE; \ 281 | } 282 | 283 | #define REFLECT_NOTIFY(id, cd) \ 284 | if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ 285 | { \ 286 | bHandled = TRUE; \ 287 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 288 | if(bHandled) \ 289 | return TRUE; \ 290 | } 291 | 292 | #define REFLECT_NOTIFY_ID(id) \ 293 | if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ 294 | { \ 295 | bHandled = TRUE; \ 296 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 297 | if(bHandled) \ 298 | return TRUE; \ 299 | } 300 | 301 | #define REFLECT_NOTIFY_CODE(cd) \ 302 | if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ 303 | { \ 304 | bHandled = TRUE; \ 305 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 306 | if(bHandled) \ 307 | return TRUE; \ 308 | } 309 | 310 | #define REFLECT_NOTIFY_RANGE(idFirst, idLast) \ 311 | if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ 312 | { \ 313 | bHandled = TRUE; \ 314 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 315 | if(bHandled) \ 316 | return TRUE; \ 317 | } 318 | 319 | #define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \ 320 | if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ 321 | { \ 322 | bHandled = TRUE; \ 323 | lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ 324 | if(bHandled) \ 325 | return TRUE; \ 326 | } 327 | 328 | 329 | /////////////////////////////////////////////////////////////////////////////// 330 | // Reflected message handler macros for message maps (for ATL 3.0) 331 | 332 | #if (_ATL_VER < 0x0700) 333 | 334 | #define REFLECTED_COMMAND_HANDLER(id, code, func) \ 335 | if(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ 336 | { \ 337 | bHandled = TRUE; \ 338 | lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ 339 | if(bHandled) \ 340 | return TRUE; \ 341 | } 342 | 343 | #define REFLECTED_COMMAND_ID_HANDLER(id, func) \ 344 | if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ 345 | { \ 346 | bHandled = TRUE; \ 347 | lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ 348 | if(bHandled) \ 349 | return TRUE; \ 350 | } 351 | 352 | #define REFLECTED_COMMAND_CODE_HANDLER(code, func) \ 353 | if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ 354 | { \ 355 | bHandled = TRUE; \ 356 | lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ 357 | if(bHandled) \ 358 | return TRUE; \ 359 | } 360 | 361 | #define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \ 362 | if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ 363 | { \ 364 | bHandled = TRUE; \ 365 | lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ 366 | if(bHandled) \ 367 | return TRUE; \ 368 | } 369 | 370 | #define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \ 371 | if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ 372 | { \ 373 | bHandled = TRUE; \ 374 | lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ 375 | if(bHandled) \ 376 | return TRUE; \ 377 | } 378 | 379 | #define REFLECTED_NOTIFY_HANDLER(id, cd, func) \ 380 | if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ 381 | { \ 382 | bHandled = TRUE; \ 383 | lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ 384 | if(bHandled) \ 385 | return TRUE; \ 386 | } 387 | 388 | #define REFLECTED_NOTIFY_ID_HANDLER(id, func) \ 389 | if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ 390 | { \ 391 | bHandled = TRUE; \ 392 | lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ 393 | if(bHandled) \ 394 | return TRUE; \ 395 | } 396 | 397 | #define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \ 398 | if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ 399 | { \ 400 | bHandled = TRUE; \ 401 | lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ 402 | if(bHandled) \ 403 | return TRUE; \ 404 | } 405 | 406 | #define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \ 407 | if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ 408 | { \ 409 | bHandled = TRUE; \ 410 | lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ 411 | if(bHandled) \ 412 | return TRUE; \ 413 | } 414 | 415 | #define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \ 416 | if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ 417 | { \ 418 | bHandled = TRUE; \ 419 | lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ 420 | if(bHandled) \ 421 | return TRUE; \ 422 | } 423 | 424 | #endif // (_ATL_VER < 0x0700) 425 | 426 | 427 | /////////////////////////////////////////////////////////////////////////////// 428 | // Dual argument helper classes (for ATL 3.0) 429 | 430 | #if (_ATL_VER < 0x0700) 431 | 432 | namespace ATL 433 | { 434 | 435 | class _U_RECT 436 | { 437 | public: 438 | _U_RECT(LPRECT lpRect) : m_lpRect(lpRect) 439 | { } 440 | _U_RECT(RECT& rc) : m_lpRect(&rc) 441 | { } 442 | LPRECT m_lpRect; 443 | }; 444 | 445 | class _U_MENUorID 446 | { 447 | public: 448 | _U_MENUorID(HMENU hMenu) : m_hMenu(hMenu) 449 | { } 450 | _U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID)) 451 | { } 452 | HMENU m_hMenu; 453 | }; 454 | 455 | class _U_STRINGorID 456 | { 457 | public: 458 | _U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString) 459 | { } 460 | _U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID)) 461 | { } 462 | LPCTSTR m_lpstr; 463 | }; 464 | 465 | }; // namespace ATL 466 | 467 | #endif // (_ATL_VER < 0x0700) 468 | 469 | 470 | namespace WTL 471 | { 472 | 473 | /////////////////////////////////////////////////////////////////////////////// 474 | // Forward notifications support for message maps (for ATL 3.0) 475 | 476 | #if (_ATL_VER < 0x0700) 477 | 478 | // forward notifications support 479 | #define FORWARD_NOTIFICATIONS() \ 480 | { \ 481 | bHandled = TRUE; \ 482 | lResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \ 483 | if(bHandled) \ 484 | return TRUE; \ 485 | } 486 | 487 | static LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 488 | { 489 | LRESULT lResult = 0; 490 | switch(uMsg) 491 | { 492 | case WM_COMMAND: 493 | case WM_NOTIFY: 494 | #ifndef _WIN32_WCE 495 | case WM_PARENTNOTIFY: 496 | #endif // !_WIN32_WCE 497 | case WM_DRAWITEM: 498 | case WM_MEASUREITEM: 499 | case WM_COMPAREITEM: 500 | case WM_DELETEITEM: 501 | case WM_VKEYTOITEM: 502 | case WM_CHARTOITEM: 503 | case WM_HSCROLL: 504 | case WM_VSCROLL: 505 | case WM_CTLCOLORBTN: 506 | case WM_CTLCOLORDLG: 507 | case WM_CTLCOLOREDIT: 508 | case WM_CTLCOLORLISTBOX: 509 | case WM_CTLCOLORMSGBOX: 510 | case WM_CTLCOLORSCROLLBAR: 511 | case WM_CTLCOLORSTATIC: 512 | lResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam); 513 | break; 514 | default: 515 | bHandled = FALSE; 516 | break; 517 | } 518 | return lResult; 519 | } 520 | 521 | #endif // (_ATL_VER < 0x0700) 522 | 523 | }; // namespace WTL 524 | 525 | #endif // __ATLWINX_H__ 526 | -------------------------------------------------------------------------------- /D/D/wtl/atlddx.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLDDX_H__ 13 | #define __ATLDDX_H__ 14 | 15 | #pragma once 16 | 17 | #ifndef __ATLAPP_H__ 18 | #error atlddx.h requires atlapp.h to be included first 19 | #endif 20 | 21 | #if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) 22 | #error Cannot use floating point DDX with _ATL_MIN_CRT defined 23 | #endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) 24 | 25 | #ifdef _ATL_USE_DDX_FLOAT 26 | #include 27 | #endif // _ATL_USE_DDX_FLOAT 28 | 29 | 30 | /////////////////////////////////////////////////////////////////////////////// 31 | // Classes in this file: 32 | // 33 | // CWinDataExchange 34 | 35 | 36 | namespace WTL 37 | { 38 | 39 | // Constants 40 | #define DDX_LOAD FALSE 41 | #define DDX_SAVE TRUE 42 | 43 | // DDX map macros 44 | #define BEGIN_DDX_MAP(thisClass) \ 45 | BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \ 46 | { \ 47 | bSaveAndValidate; \ 48 | nCtlID; 49 | 50 | #define DDX_TEXT(nID, var) \ 51 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 52 | { \ 53 | if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \ 54 | return FALSE; \ 55 | } 56 | 57 | #define DDX_TEXT_LEN(nID, var, len) \ 58 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 59 | { \ 60 | if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \ 61 | return FALSE; \ 62 | } 63 | 64 | #define DDX_INT(nID, var) \ 65 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 66 | { \ 67 | if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \ 68 | return FALSE; \ 69 | } 70 | 71 | #define DDX_INT_RANGE(nID, var, min, max) \ 72 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 73 | { \ 74 | if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \ 75 | return FALSE; \ 76 | } 77 | 78 | #define DDX_UINT(nID, var) \ 79 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 80 | { \ 81 | if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \ 82 | return FALSE; \ 83 | } 84 | 85 | #define DDX_UINT_RANGE(nID, var, min, max) \ 86 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 87 | { \ 88 | if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \ 89 | return FALSE; \ 90 | } 91 | 92 | #ifdef _ATL_USE_DDX_FLOAT 93 | #define DDX_FLOAT(nID, var) \ 94 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 95 | { \ 96 | if(!DDX_Float(nID, var, bSaveAndValidate)) \ 97 | return FALSE; \ 98 | } 99 | 100 | #define DDX_FLOAT_RANGE(nID, var, min, max) \ 101 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 102 | { \ 103 | if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \ 104 | return FALSE; \ 105 | } 106 | #define DDX_FLOAT_P(nID, var, precision) \ 107 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 108 | { \ 109 | if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \ 110 | return FALSE; \ 111 | } 112 | 113 | #define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \ 114 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 115 | { \ 116 | if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \ 117 | return FALSE; \ 118 | } 119 | #endif // _ATL_USE_DDX_FLOAT 120 | 121 | #define DDX_CONTROL(nID, obj) \ 122 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 123 | DDX_Control(nID, obj, bSaveAndValidate); 124 | 125 | #define DDX_CONTROL_HANDLE(nID, obj) \ 126 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 127 | DDX_Control_Handle(nID, obj, bSaveAndValidate); 128 | 129 | #define DDX_CHECK(nID, var) \ 130 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 131 | DDX_Check(nID, var, bSaveAndValidate); 132 | 133 | #define DDX_RADIO(nID, var) \ 134 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 135 | DDX_Radio(nID, var, bSaveAndValidate); 136 | 137 | #define END_DDX_MAP() \ 138 | return TRUE; \ 139 | } 140 | 141 | // DDX support for Tab, Combo, ListBox and ListView selection index 142 | // Note: Specialized versions require atlctrls.h to be included first 143 | #if (_MSC_VER >= 1300) 144 | 145 | #define DDX_INDEX(CtrlClass, nID, var) \ 146 | if(nCtlID == (UINT)-1 || nCtlID == nID) \ 147 | DDX_Index(nID, var, bSaveAndValidate); 148 | 149 | #ifdef __ATLCTRLS_H__ 150 | #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var) 151 | #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var) 152 | #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var) 153 | #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var) 154 | #endif // __ATLCTRLS_H__ 155 | 156 | #endif // (_MSC_VER >= 1300) 157 | 158 | 159 | /////////////////////////////////////////////////////////////////////////////// 160 | // CWinDataExchange - provides support for DDX 161 | 162 | template 163 | class CWinDataExchange 164 | { 165 | public: 166 | // Data exchange method - override in your derived class 167 | BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1) 168 | { 169 | // this one should never be called, override it in 170 | // your derived class by implementing DDX map 171 | ATLASSERT(FALSE); 172 | return FALSE; 173 | } 174 | 175 | // Helpers for validation error reporting 176 | enum _XDataType 177 | { 178 | ddxDataNull = 0, 179 | ddxDataText = 1, 180 | ddxDataInt = 2, 181 | ddxDataFloat = 3, 182 | ddxDataDouble = 4 183 | }; 184 | 185 | struct _XTextData 186 | { 187 | int nLength; 188 | int nMaxLength; 189 | }; 190 | 191 | struct _XIntData 192 | { 193 | long nVal; 194 | long nMin; 195 | long nMax; 196 | }; 197 | 198 | struct _XFloatData 199 | { 200 | double nVal; 201 | double nMin; 202 | double nMax; 203 | }; 204 | 205 | struct _XData 206 | { 207 | _XDataType nDataType; 208 | union 209 | { 210 | _XTextData textData; 211 | _XIntData intData; 212 | _XFloatData floatData; 213 | }; 214 | }; 215 | 216 | // Text exchange 217 | BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) 218 | { 219 | T* pT = static_cast(this); 220 | BOOL bSuccess = TRUE; 221 | 222 | if(bSave) 223 | { 224 | HWND hWndCtrl = pT->GetDlgItem(nID); 225 | int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR)); 226 | if(nRetLen < ::GetWindowTextLength(hWndCtrl)) 227 | bSuccess = FALSE; 228 | } 229 | else 230 | { 231 | ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); 232 | bSuccess = pT->SetDlgItemText(nID, lpstrText); 233 | } 234 | 235 | if(!bSuccess) 236 | { 237 | pT->OnDataExchangeError(nID, bSave); 238 | } 239 | else if(bSave && bValidate) // validation 240 | { 241 | ATLASSERT(nLength > 0); 242 | if(lstrlen(lpstrText) > nLength) 243 | { 244 | _XData data = { ddxDataText }; 245 | data.textData.nLength = lstrlen(lpstrText); 246 | data.textData.nMaxLength = nLength; 247 | pT->OnDataValidateError(nID, bSave, data); 248 | bSuccess = FALSE; 249 | } 250 | } 251 | return bSuccess; 252 | } 253 | 254 | BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) 255 | { 256 | T* pT = static_cast(this); 257 | BOOL bSuccess = TRUE; 258 | 259 | if(bSave) 260 | { 261 | bSuccess = pT->GetDlgItemText(nID, bstrText); 262 | } 263 | else 264 | { 265 | USES_CONVERSION; 266 | LPTSTR lpstrText = OLE2T(bstrText); 267 | ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); 268 | bSuccess = pT->SetDlgItemText(nID, lpstrText); 269 | } 270 | 271 | if(!bSuccess) 272 | { 273 | pT->OnDataExchangeError(nID, bSave); 274 | } 275 | else if(bSave && bValidate) // validation 276 | { 277 | ATLASSERT(nLength > 0); 278 | if((int)::SysStringLen(bstrText) > nLength) 279 | { 280 | _XData data = { ddxDataText }; 281 | data.textData.nLength = (int)::SysStringLen(bstrText); 282 | data.textData.nMaxLength = nLength; 283 | pT->OnDataValidateError(nID, bSave, data); 284 | bSuccess = FALSE; 285 | } 286 | } 287 | return bSuccess; 288 | } 289 | 290 | BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) 291 | { 292 | T* pT = static_cast(this); 293 | BOOL bSuccess = TRUE; 294 | 295 | if(bSave) 296 | { 297 | bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText); 298 | } 299 | else 300 | { 301 | USES_CONVERSION; 302 | LPTSTR lpstrText = OLE2T(bstrText); 303 | ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); 304 | bSuccess = pT->SetDlgItemText(nID, lpstrText); 305 | } 306 | 307 | if(!bSuccess) 308 | { 309 | pT->OnDataExchangeError(nID, bSave); 310 | } 311 | else if(bSave && bValidate) // validation 312 | { 313 | ATLASSERT(nLength > 0); 314 | if((int)bstrText.Length() > nLength) 315 | { 316 | _XData data = { ddxDataText }; 317 | data.textData.nLength = (int)bstrText.Length(); 318 | data.textData.nMaxLength = nLength; 319 | pT->OnDataValidateError(nID, bSave, data); 320 | bSuccess = FALSE; 321 | } 322 | } 323 | return bSuccess; 324 | } 325 | 326 | #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) 327 | BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) 328 | { 329 | T* pT = static_cast(this); 330 | BOOL bSuccess = TRUE; 331 | 332 | if(bSave) 333 | { 334 | HWND hWndCtrl = pT->GetDlgItem(nID); 335 | int nLen = ::GetWindowTextLength(hWndCtrl); 336 | int nRetLen = -1; 337 | LPTSTR lpstr = strText.GetBufferSetLength(nLen); 338 | if(lpstr != NULL) 339 | { 340 | nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1); 341 | strText.ReleaseBuffer(); 342 | } 343 | if(nRetLen < nLen) 344 | bSuccess = FALSE; 345 | } 346 | else 347 | { 348 | bSuccess = pT->SetDlgItemText(nID, strText); 349 | } 350 | 351 | if(!bSuccess) 352 | { 353 | pT->OnDataExchangeError(nID, bSave); 354 | } 355 | else if(bSave && bValidate) // validation 356 | { 357 | ATLASSERT(nLength > 0); 358 | if(strText.GetLength() > nLength) 359 | { 360 | _XData data = { ddxDataText }; 361 | data.textData.nLength = strText.GetLength(); 362 | data.textData.nMaxLength = nLength; 363 | pT->OnDataValidateError(nID, bSave, data); 364 | bSuccess = FALSE; 365 | } 366 | } 367 | return bSuccess; 368 | } 369 | #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) 370 | 371 | // Numeric exchange 372 | template 373 | BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) 374 | { 375 | T* pT = static_cast(this); 376 | BOOL bSuccess = TRUE; 377 | 378 | if(bSave) 379 | { 380 | nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); 381 | } 382 | else 383 | { 384 | ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); 385 | bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); 386 | } 387 | 388 | if(!bSuccess) 389 | { 390 | pT->OnDataExchangeError(nID, bSave); 391 | } 392 | else if(bSave && bValidate) // validation 393 | { 394 | ATLASSERT(nMin != nMax); 395 | if(nVal < nMin || nVal > nMax) 396 | { 397 | _XData data = { ddxDataInt }; 398 | data.intData.nVal = (long)nVal; 399 | data.intData.nMin = (long)nMin; 400 | data.intData.nMax = (long)nMax; 401 | pT->OnDataValidateError(nID, bSave, data); 402 | bSuccess = FALSE; 403 | } 404 | } 405 | return bSuccess; 406 | } 407 | 408 | // Float exchange 409 | #ifdef _ATL_USE_DDX_FLOAT 410 | static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d) 411 | { 412 | ATLASSERT(lpszText != NULL); 413 | while (*lpszText == _T(' ') || *lpszText == _T('\t')) 414 | lpszText++; 415 | 416 | TCHAR chFirst = lpszText[0]; 417 | d = _tcstod(lpszText, (LPTSTR*)&lpszText); 418 | if (d == 0.0 && chFirst != _T('0')) 419 | return FALSE; // could not convert 420 | while (*lpszText == _T(' ') || *lpszText == _T('\t')) 421 | lpszText++; 422 | 423 | if (*lpszText != _T('\0')) 424 | return FALSE; // not terminated properly 425 | 426 | return TRUE; 427 | } 428 | 429 | BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG) 430 | { 431 | T* pT = static_cast(this); 432 | BOOL bSuccess = TRUE; 433 | const int cchBuff = 32; 434 | TCHAR szBuff[cchBuff] = { 0 }; 435 | 436 | if(bSave) 437 | { 438 | pT->GetDlgItemText(nID, szBuff, cchBuff); 439 | double d = 0; 440 | if(_AtlSimpleFloatParse(szBuff, d)) 441 | nVal = (float)d; 442 | else 443 | bSuccess = FALSE; 444 | } 445 | else 446 | { 447 | ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); 448 | SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); 449 | bSuccess = pT->SetDlgItemText(nID, szBuff); 450 | } 451 | 452 | if(!bSuccess) 453 | { 454 | pT->OnDataExchangeError(nID, bSave); 455 | } 456 | else if(bSave && bValidate) // validation 457 | { 458 | ATLASSERT(nMin != nMax); 459 | if(nVal < nMin || nVal > nMax) 460 | { 461 | _XData data = { ddxDataFloat }; 462 | data.floatData.nVal = (double)nVal; 463 | data.floatData.nMin = (double)nMin; 464 | data.floatData.nMax = (double)nMax; 465 | pT->OnDataValidateError(nID, bSave, data); 466 | bSuccess = FALSE; 467 | } 468 | } 469 | return bSuccess; 470 | } 471 | 472 | BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG) 473 | { 474 | T* pT = static_cast(this); 475 | BOOL bSuccess = TRUE; 476 | const int cchBuff = 32; 477 | TCHAR szBuff[cchBuff] = { 0 }; 478 | 479 | if(bSave) 480 | { 481 | pT->GetDlgItemText(nID, szBuff, cchBuff); 482 | double d = 0; 483 | if(_AtlSimpleFloatParse(szBuff, d)) 484 | nVal = d; 485 | else 486 | bSuccess = FALSE; 487 | } 488 | else 489 | { 490 | ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); 491 | SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); 492 | bSuccess = pT->SetDlgItemText(nID, szBuff); 493 | } 494 | 495 | if(!bSuccess) 496 | { 497 | pT->OnDataExchangeError(nID, bSave); 498 | } 499 | else if(bSave && bValidate) // validation 500 | { 501 | ATLASSERT(nMin != nMax); 502 | if(nVal < nMin || nVal > nMax) 503 | { 504 | _XData data = { ddxDataFloat }; 505 | data.floatData.nVal = nVal; 506 | data.floatData.nMin = nMin; 507 | data.floatData.nMax = nMax; 508 | pT->OnDataValidateError(nID, bSave, data); 509 | bSuccess = FALSE; 510 | } 511 | } 512 | return bSuccess; 513 | } 514 | #endif // _ATL_USE_DDX_FLOAT 515 | 516 | // Full control subclassing (for CWindowImpl derived controls) 517 | template 518 | void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave) 519 | { 520 | if(!bSave && ctrl.m_hWnd == NULL) 521 | { 522 | T* pT = static_cast(this); 523 | ctrl.SubclassWindow(pT->GetDlgItem(nID)); 524 | } 525 | } 526 | 527 | // Simple control attaching (for HWND wrapper controls) 528 | template 529 | void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave) 530 | { 531 | if(!bSave && ctrl.m_hWnd == NULL) 532 | { 533 | T* pT = static_cast(this); 534 | ctrl = pT->GetDlgItem(nID); 535 | } 536 | } 537 | 538 | // Control state 539 | void DDX_Check(UINT nID, int& nValue, BOOL bSave) 540 | { 541 | T* pT = static_cast(this); 542 | HWND hWndCtrl = pT->GetDlgItem(nID); 543 | if(bSave) 544 | { 545 | nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); 546 | ATLASSERT(nValue >= 0 && nValue <= 2); 547 | } 548 | else 549 | { 550 | if(nValue < 0 || nValue > 2) 551 | { 552 | ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue); 553 | nValue = 0; // default to off 554 | } 555 | ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L); 556 | } 557 | } 558 | 559 | // variant that supports bool (checked/not-checked, no intermediate state) 560 | void DDX_Check(UINT nID, bool& bCheck, BOOL bSave) 561 | { 562 | int nValue = bCheck ? 1 : 0; 563 | DDX_Check(nID, nValue, bSave); 564 | 565 | if(bSave) 566 | { 567 | if(nValue == 2) 568 | ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue); 569 | bCheck = (nValue == 1); 570 | } 571 | } 572 | 573 | void DDX_Radio(UINT nID, int& nValue, BOOL bSave) 574 | { 575 | T* pT = static_cast(this); 576 | HWND hWndCtrl = pT->GetDlgItem(nID); 577 | ATLASSERT(hWndCtrl != NULL); 578 | 579 | // must be first in a group of auto radio buttons 580 | ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP); 581 | ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); 582 | 583 | if(bSave) 584 | nValue = -1; // value if none found 585 | 586 | // walk all children in group 587 | int nButton = 0; 588 | do 589 | { 590 | if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) 591 | { 592 | // control in group is a radio button 593 | if(bSave) 594 | { 595 | if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) 596 | { 597 | ATLASSERT(nValue == -1); // only set once 598 | nValue = nButton; 599 | } 600 | } 601 | else 602 | { 603 | // select button 604 | ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L); 605 | } 606 | nButton++; 607 | } 608 | else 609 | { 610 | ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n")); 611 | } 612 | hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); 613 | } 614 | while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)); 615 | } 616 | 617 | // DDX support for Tab, Combo, ListBox and ListView selection index 618 | #if (_MSC_VER >= 1300) 619 | template 620 | INT _getSel(TCtrl& tCtrl) 621 | { 622 | return tCtrl.GetCurSel(); 623 | } 624 | 625 | template 626 | void _setSel(TCtrl& tCtrl, INT iSel) 627 | { 628 | if(iSel < 0) 629 | tCtrl.SetCurSel(-1); 630 | else 631 | tCtrl.SetCurSel(iSel); 632 | } 633 | 634 | #ifdef __ATLCTRLS_H__ 635 | // ListViewCtrl specialization 636 | template <> 637 | INT _getSel(WTL::CListViewCtrl& tCtrl) 638 | { 639 | return tCtrl.GetSelectedIndex(); 640 | } 641 | 642 | template <> 643 | void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel) 644 | { 645 | if(iSel < 0) 646 | tCtrl.SelectItem(-1); 647 | else 648 | tCtrl.SelectItem(iSel); 649 | } 650 | #endif // __ATLCTRLS_H__ 651 | 652 | template 653 | void DDX_Index(UINT nID, INT& nVal, BOOL bSave) 654 | { 655 | T* pT = static_cast(this); 656 | TCtrl ctrl(pT->GetDlgItem(nID)); 657 | 658 | if(bSave) 659 | nVal = _getSel(ctrl); 660 | else 661 | _setSel(ctrl, nVal); 662 | } 663 | #endif // (_MSC_VER >= 1300) 664 | 665 | // Overrideables 666 | void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) 667 | { 668 | // Override to display an error message 669 | ::MessageBeep((UINT)-1); 670 | T* pT = static_cast(this); 671 | ::SetFocus(pT->GetDlgItem(nCtrlID)); 672 | } 673 | 674 | void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) 675 | { 676 | // Override to display an error message 677 | ::MessageBeep((UINT)-1); 678 | T* pT = static_cast(this); 679 | ::SetFocus(pT->GetDlgItem(nCtrlID)); 680 | } 681 | }; 682 | 683 | }; // namespace WTL 684 | 685 | #endif // __ATLDDX_H__ 686 | -------------------------------------------------------------------------------- /D/D/wtl/atlsplit.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLSPLIT_H__ 13 | #define __ATLSPLIT_H__ 14 | 15 | #pragma once 16 | 17 | #ifndef __ATLAPP_H__ 18 | #error atlsplit.h requires atlapp.h to be included first 19 | #endif 20 | 21 | #ifndef __ATLWIN_H__ 22 | #error atlsplit.h requires atlwin.h to be included first 23 | #endif 24 | 25 | 26 | /////////////////////////////////////////////////////////////////////////////// 27 | // Classes in this file: 28 | // 29 | // CSplitterImpl 30 | // CSplitterWindowImpl 31 | // CSplitterWindowT 32 | 33 | 34 | namespace WTL 35 | { 36 | 37 | /////////////////////////////////////////////////////////////////////////////// 38 | // CSplitterImpl - Provides splitter support to any window 39 | 40 | // Splitter panes constants 41 | #define SPLIT_PANE_LEFT 0 42 | #define SPLIT_PANE_RIGHT 1 43 | #define SPLIT_PANE_TOP SPLIT_PANE_LEFT 44 | #define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT 45 | #define SPLIT_PANE_NONE -1 46 | 47 | // Splitter extended styles 48 | #define SPLIT_PROPORTIONAL 0x00000001 49 | #define SPLIT_NONINTERACTIVE 0x00000002 50 | #define SPLIT_RIGHTALIGNED 0x00000004 51 | #define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED 52 | #define SPLIT_GRADIENTBAR 0x00000008 53 | #define SPLIT_FIXEDBARSIZE 0x00000010 54 | 55 | // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are 56 | // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL 57 | 58 | 59 | template 60 | class CSplitterImpl 61 | { 62 | public: 63 | enum { m_nPanesCount = 2, m_nPropMax = 10000 }; 64 | 65 | HWND m_hWndPane[m_nPanesCount]; 66 | RECT m_rcSplitter; 67 | int m_xySplitterPos; 68 | int m_nDefActivePane; 69 | int m_cxySplitBar; // splitter bar width/height 70 | static HCURSOR m_hCursor; 71 | int m_cxyMin; // minimum pane size 72 | int m_cxyBarEdge; // splitter bar edge 73 | bool m_bFullDrag; 74 | int m_cxyDragOffset; 75 | int m_nProportionalPos; 76 | bool m_bUpdateProportionalPos; 77 | DWORD m_dwExtendedStyle; // splitter specific extended styles 78 | int m_nSinglePane; // single pane mode 79 | 80 | // Constructor 81 | CSplitterImpl() : 82 | m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE), 83 | m_cxySplitBar(4), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true), 84 | m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true), 85 | m_dwExtendedStyle(SPLIT_PROPORTIONAL), 86 | m_nSinglePane(SPLIT_PANE_NONE) 87 | { 88 | m_hWndPane[SPLIT_PANE_LEFT] = NULL; 89 | m_hWndPane[SPLIT_PANE_RIGHT] = NULL; 90 | 91 | ::SetRectEmpty(&m_rcSplitter); 92 | 93 | if(m_hCursor == NULL) 94 | { 95 | CStaticDataInitCriticalSectionLock lock; 96 | if(FAILED(lock.Lock())) 97 | { 98 | ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n")); 99 | ATLASSERT(FALSE); 100 | return; 101 | } 102 | 103 | if(m_hCursor == NULL) 104 | m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS); 105 | 106 | lock.Unlock(); 107 | } 108 | } 109 | 110 | // Attributes 111 | void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) 112 | { 113 | if(lpRect == NULL) 114 | { 115 | T* pT = static_cast(this); 116 | pT->GetClientRect(&m_rcSplitter); 117 | } 118 | else 119 | { 120 | m_rcSplitter = *lpRect; 121 | } 122 | 123 | if(IsProportional()) 124 | UpdateProportionalPos(); 125 | else if(IsRightAligned()) 126 | UpdateRightAlignPos(); 127 | 128 | if(bUpdate) 129 | UpdateSplitterLayout(); 130 | } 131 | 132 | void GetSplitterRect(LPRECT lpRect) const 133 | { 134 | ATLASSERT(lpRect != NULL); 135 | *lpRect = m_rcSplitter; 136 | } 137 | 138 | bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) 139 | { 140 | if(xyPos == -1) // -1 == middle 141 | { 142 | if(t_bVertical) 143 | xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; 144 | else 145 | xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; 146 | } 147 | 148 | // Adjust if out of valid range 149 | int cxyMax = 0; 150 | if(t_bVertical) 151 | cxyMax = m_rcSplitter.right - m_rcSplitter.left; 152 | else 153 | cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; 154 | 155 | if(xyPos < m_cxyMin + m_cxyBarEdge) 156 | xyPos = m_cxyMin; 157 | else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) 158 | xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; 159 | 160 | // Set new position and update if requested 161 | bool bRet = (m_xySplitterPos != xyPos); 162 | m_xySplitterPos = xyPos; 163 | 164 | if(m_bUpdateProportionalPos) 165 | { 166 | if(IsProportional()) 167 | StoreProportionalPos(); 168 | else if(IsRightAligned()) 169 | StoreRightAlignPos(); 170 | } 171 | else 172 | { 173 | m_bUpdateProportionalPos = true; 174 | } 175 | 176 | if(bUpdate && bRet) 177 | UpdateSplitterLayout(); 178 | 179 | return bRet; 180 | } 181 | 182 | void SetSplitterPosPct(int nPct, bool bUpdate = true) 183 | { 184 | ATLASSERT(nPct >= 0 && nPct <= 100); 185 | 186 | m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); 187 | UpdateProportionalPos(); 188 | 189 | if(bUpdate) 190 | UpdateSplitterLayout(); 191 | } 192 | 193 | int GetSplitterPos() const 194 | { 195 | return m_xySplitterPos; 196 | } 197 | 198 | bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) 199 | { 200 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE); 201 | if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE)) 202 | return false; 203 | 204 | if(nPane != SPLIT_PANE_NONE) 205 | { 206 | if(!::IsWindowVisible(m_hWndPane[nPane])) 207 | ::ShowWindow(m_hWndPane[nPane], SW_SHOW); 208 | int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; 209 | ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE); 210 | if(m_nDefActivePane != nPane) 211 | m_nDefActivePane = nPane; 212 | } 213 | else if(m_nSinglePane != SPLIT_PANE_NONE) 214 | { 215 | int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; 216 | ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); 217 | } 218 | 219 | m_nSinglePane = nPane; 220 | UpdateSplitterLayout(); 221 | return true; 222 | } 223 | 224 | int GetSinglePaneMode() const 225 | { 226 | return m_nSinglePane; 227 | } 228 | 229 | DWORD GetSplitterExtendedStyle() const 230 | { 231 | return m_dwExtendedStyle; 232 | } 233 | 234 | DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) 235 | { 236 | DWORD dwPrevStyle = m_dwExtendedStyle; 237 | if(dwMask == 0) 238 | m_dwExtendedStyle = dwExtendedStyle; 239 | else 240 | m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); 241 | #ifdef _DEBUG 242 | if(IsProportional() && IsRightAligned()) 243 | ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n")); 244 | #endif // _DEBUG 245 | return dwPrevStyle; 246 | } 247 | 248 | // Splitter operations 249 | void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true) 250 | { 251 | m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; 252 | m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; 253 | ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]); 254 | if(bUpdate) 255 | UpdateSplitterLayout(); 256 | } 257 | 258 | bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) 259 | { 260 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); 261 | 262 | if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) 263 | return false; 264 | m_hWndPane[nPane] = hWnd; 265 | ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]); 266 | if(bUpdate) 267 | UpdateSplitterLayout(); 268 | return true; 269 | } 270 | 271 | HWND GetSplitterPane(int nPane) const 272 | { 273 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); 274 | 275 | if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) 276 | return false; 277 | return m_hWndPane[nPane]; 278 | } 279 | 280 | bool SetActivePane(int nPane) 281 | { 282 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); 283 | 284 | if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) 285 | return false; 286 | if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane) 287 | return false; 288 | ::SetFocus(m_hWndPane[nPane]); 289 | m_nDefActivePane = nPane; 290 | return true; 291 | } 292 | 293 | int GetActivePane() const 294 | { 295 | int nRet = SPLIT_PANE_NONE; 296 | HWND hWndFocus = ::GetFocus(); 297 | if(hWndFocus != NULL) 298 | { 299 | for(int nPane = 0; nPane < m_nPanesCount; nPane++) 300 | { 301 | if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus)) 302 | { 303 | nRet = nPane; 304 | break; 305 | } 306 | } 307 | } 308 | return nRet; 309 | } 310 | 311 | bool ActivateNextPane(bool bNext = true) 312 | { 313 | int nPane = m_nSinglePane; 314 | if(nPane == SPLIT_PANE_NONE) 315 | { 316 | switch(GetActivePane()) 317 | { 318 | case SPLIT_PANE_LEFT: 319 | nPane = SPLIT_PANE_RIGHT; 320 | break; 321 | case SPLIT_PANE_RIGHT: 322 | nPane = SPLIT_PANE_LEFT; 323 | break; 324 | default: 325 | nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT; 326 | break; 327 | } 328 | } 329 | return SetActivePane(nPane); 330 | } 331 | 332 | bool SetDefaultActivePane(int nPane) 333 | { 334 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); 335 | 336 | if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) 337 | return false; 338 | m_nDefActivePane = nPane; 339 | return true; 340 | } 341 | 342 | bool SetDefaultActivePane(HWND hWnd) 343 | { 344 | for(int nPane = 0; nPane < m_nPanesCount; nPane++) 345 | { 346 | if(hWnd == m_hWndPane[nPane]) 347 | { 348 | m_nDefActivePane = nPane; 349 | return true; 350 | } 351 | } 352 | return false; // not found 353 | } 354 | 355 | int GetDefaultActivePane() const 356 | { 357 | return m_nDefActivePane; 358 | } 359 | 360 | void DrawSplitter(CDCHandle dc) 361 | { 362 | ATLASSERT(dc.m_hDC != NULL); 363 | if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) 364 | return; 365 | 366 | T* pT = static_cast(this); 367 | if(m_nSinglePane == SPLIT_PANE_NONE) 368 | { 369 | pT->DrawSplitterBar(dc); 370 | 371 | for(int nPane = 0; nPane < m_nPanesCount; nPane++) 372 | { 373 | if(m_hWndPane[nPane] == NULL) 374 | pT->DrawSplitterPane(dc, nPane); 375 | } 376 | } 377 | else 378 | { 379 | if(m_hWndPane[m_nSinglePane] == NULL) 380 | pT->DrawSplitterPane(dc, m_nSinglePane); 381 | } 382 | } 383 | 384 | // Overrideables 385 | void DrawSplitterBar(CDCHandle dc) 386 | { 387 | RECT rect = { 0 }; 388 | if(GetSplitterBarRect(&rect)) 389 | { 390 | dc.FillRect(&rect, COLOR_3DFACE); 391 | 392 | #if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420)) 393 | if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0) 394 | { 395 | RECT rect2 = rect; 396 | if(t_bVertical) 397 | rect2.left = (rect.left + rect.right) / 2 - 1; 398 | else 399 | rect2.top = (rect.top + rect.bottom) / 2 - 1; 400 | 401 | dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), t_bVertical); 402 | } 403 | #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) 404 | 405 | // draw 3D edge if needed 406 | T* pT = static_cast(this); 407 | if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) 408 | dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); 409 | } 410 | } 411 | 412 | // called only if pane is empty 413 | void DrawSplitterPane(CDCHandle dc, int nPane) 414 | { 415 | RECT rect = { 0 }; 416 | if(GetSplitterPaneRect(nPane, &rect)) 417 | { 418 | T* pT = static_cast(this); 419 | if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) 420 | dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 421 | dc.FillRect(&rect, COLOR_APPWORKSPACE); 422 | } 423 | } 424 | 425 | // Message map and handlers 426 | BEGIN_MSG_MAP(CSplitterImpl) 427 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 428 | MESSAGE_HANDLER(WM_PAINT, OnPaint) 429 | #ifndef _WIN32_WCE 430 | MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) 431 | #endif // !_WIN32_WCE 432 | if(IsInteractive()) 433 | { 434 | MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) 435 | MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 436 | MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) 437 | MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) 438 | MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick) 439 | MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) 440 | } 441 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 442 | #ifndef _WIN32_WCE 443 | MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) 444 | #endif // !_WIN32_WCE 445 | MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) 446 | END_MSG_MAP() 447 | 448 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 449 | { 450 | T* pT = static_cast(this); 451 | pT->GetSystemSettings(false); 452 | 453 | bHandled = FALSE; 454 | return 1; 455 | } 456 | 457 | LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 458 | { 459 | T* pT = static_cast(this); 460 | // try setting position if not set 461 | if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) 462 | pT->SetSplitterPos(); 463 | // do painting 464 | CPaintDC dc(pT->m_hWnd); 465 | pT->DrawSplitter(dc.m_hDC); 466 | return 0; 467 | } 468 | 469 | LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 470 | { 471 | T* pT = static_cast(this); 472 | if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT) 473 | { 474 | DWORD dwPos = ::GetMessagePos(); 475 | POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; 476 | pT->ScreenToClient(&ptPos); 477 | if(IsOverSplitterBar(ptPos.x, ptPos.y)) 478 | return 1; 479 | } 480 | 481 | bHandled = FALSE; 482 | return 0; 483 | } 484 | 485 | LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 486 | { 487 | T* pT = static_cast(this); 488 | int xPos = GET_X_LPARAM(lParam); 489 | int yPos = GET_Y_LPARAM(lParam); 490 | if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd) 491 | { 492 | int xyNewSplitPos = 0; 493 | if(t_bVertical) 494 | xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset; 495 | else 496 | xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset; 497 | 498 | if(xyNewSplitPos == -1) // avoid -1, that means middle 499 | xyNewSplitPos = -2; 500 | 501 | if(m_xySplitterPos != xyNewSplitPos) 502 | { 503 | if(m_bFullDrag) 504 | { 505 | if(pT->SetSplitterPos(xyNewSplitPos, true)) 506 | pT->UpdateWindow(); 507 | } 508 | else 509 | { 510 | DrawGhostBar(); 511 | pT->SetSplitterPos(xyNewSplitPos, false); 512 | DrawGhostBar(); 513 | } 514 | } 515 | } 516 | else // not dragging, just set cursor 517 | { 518 | if(IsOverSplitterBar(xPos, yPos)) 519 | ::SetCursor(m_hCursor); 520 | bHandled = FALSE; 521 | } 522 | 523 | return 0; 524 | } 525 | 526 | LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) 527 | { 528 | int xPos = GET_X_LPARAM(lParam); 529 | int yPos = GET_Y_LPARAM(lParam); 530 | if(IsOverSplitterBar(xPos, yPos)) 531 | { 532 | T* pT = static_cast(this); 533 | pT->SetCapture(); 534 | ::SetCursor(m_hCursor); 535 | if(!m_bFullDrag) 536 | DrawGhostBar(); 537 | if(t_bVertical) 538 | m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos; 539 | else 540 | m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos; 541 | } 542 | bHandled = FALSE; 543 | return 1; 544 | } 545 | 546 | LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 547 | { 548 | ::ReleaseCapture(); 549 | bHandled = FALSE; 550 | return 1; 551 | } 552 | 553 | LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 554 | { 555 | T* pT = static_cast(this); 556 | pT->SetSplitterPos(); // middle 557 | return 0; 558 | } 559 | 560 | LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 561 | { 562 | if(!m_bFullDrag) 563 | { 564 | DrawGhostBar(); 565 | UpdateSplitterLayout(); 566 | T* pT = static_cast(this); 567 | pT->UpdateWindow(); 568 | } 569 | return 0; 570 | } 571 | 572 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled) 573 | { 574 | if(m_nSinglePane == SPLIT_PANE_NONE) 575 | { 576 | if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT) 577 | ::SetFocus(m_hWndPane[m_nDefActivePane]); 578 | } 579 | else 580 | { 581 | ::SetFocus(m_hWndPane[m_nSinglePane]); 582 | } 583 | bHandled = FALSE; 584 | return 1; 585 | } 586 | 587 | #ifndef _WIN32_WCE 588 | LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) 589 | { 590 | T* pT = static_cast(this); 591 | LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); 592 | if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT) 593 | { 594 | DWORD dwPos = ::GetMessagePos(); 595 | POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; 596 | pT->ScreenToClient(&pt); 597 | RECT rcPane = { 0 }; 598 | for(int nPane = 0; nPane < m_nPanesCount; nPane++) 599 | { 600 | if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt)) 601 | { 602 | m_nDefActivePane = nPane; 603 | break; 604 | } 605 | } 606 | } 607 | return lRet; 608 | } 609 | #endif // !_WIN32_WCE 610 | 611 | LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 612 | { 613 | T* pT = static_cast(this); 614 | pT->GetSystemSettings(true); 615 | 616 | return 0; 617 | } 618 | 619 | // Implementation - internal helpers 620 | void UpdateSplitterLayout() 621 | { 622 | if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) 623 | return; 624 | 625 | T* pT = static_cast(this); 626 | RECT rect = { 0 }; 627 | if(m_nSinglePane == SPLIT_PANE_NONE) 628 | { 629 | if(GetSplitterBarRect(&rect)) 630 | pT->InvalidateRect(&rect); 631 | 632 | for(int nPane = 0; nPane < m_nPanesCount; nPane++) 633 | { 634 | if(GetSplitterPaneRect(nPane, &rect)) 635 | { 636 | if(m_hWndPane[nPane] != NULL) 637 | ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); 638 | else 639 | pT->InvalidateRect(&rect); 640 | } 641 | } 642 | } 643 | else 644 | { 645 | if(GetSplitterPaneRect(m_nSinglePane, &rect)) 646 | { 647 | if(m_hWndPane[m_nSinglePane] != NULL) 648 | ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); 649 | else 650 | pT->InvalidateRect(&rect); 651 | } 652 | } 653 | } 654 | 655 | bool GetSplitterBarRect(LPRECT lpRect) const 656 | { 657 | ATLASSERT(lpRect != NULL); 658 | if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1) 659 | return false; 660 | 661 | if(t_bVertical) 662 | { 663 | lpRect->left = m_rcSplitter.left + m_xySplitterPos; 664 | lpRect->top = m_rcSplitter.top; 665 | lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; 666 | lpRect->bottom = m_rcSplitter.bottom; 667 | } 668 | else 669 | { 670 | lpRect->left = m_rcSplitter.left; 671 | lpRect->top = m_rcSplitter.top + m_xySplitterPos; 672 | lpRect->right = m_rcSplitter.right; 673 | lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; 674 | } 675 | 676 | return true; 677 | } 678 | 679 | bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const 680 | { 681 | ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); 682 | ATLASSERT(lpRect != NULL); 683 | bool bRet = true; 684 | if(m_nSinglePane != SPLIT_PANE_NONE) 685 | { 686 | if(nPane == m_nSinglePane) 687 | *lpRect = m_rcSplitter; 688 | else 689 | bRet = false; 690 | } 691 | else if(nPane == SPLIT_PANE_LEFT) 692 | { 693 | if(t_bVertical) 694 | { 695 | lpRect->left = m_rcSplitter.left; 696 | lpRect->top = m_rcSplitter.top; 697 | lpRect->right = m_rcSplitter.left + m_xySplitterPos; 698 | lpRect->bottom = m_rcSplitter.bottom; 699 | } 700 | else 701 | { 702 | lpRect->left = m_rcSplitter.left; 703 | lpRect->top = m_rcSplitter.top; 704 | lpRect->right = m_rcSplitter.right; 705 | lpRect->bottom = m_rcSplitter.top + m_xySplitterPos; 706 | } 707 | } 708 | else if(nPane == SPLIT_PANE_RIGHT) 709 | { 710 | if(t_bVertical) 711 | { 712 | lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; 713 | lpRect->top = m_rcSplitter.top; 714 | lpRect->right = m_rcSplitter.right; 715 | lpRect->bottom = m_rcSplitter.bottom; 716 | } 717 | else 718 | { 719 | lpRect->left = m_rcSplitter.left; 720 | lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; 721 | lpRect->right = m_rcSplitter.right; 722 | lpRect->bottom = m_rcSplitter.bottom; 723 | } 724 | } 725 | else 726 | { 727 | bRet = false; 728 | } 729 | return bRet; 730 | } 731 | 732 | bool IsOverSplitterRect(int x, int y) const 733 | { 734 | // -1 == don't check 735 | return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) && 736 | (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom))); 737 | } 738 | 739 | bool IsOverSplitterBar(int x, int y) const 740 | { 741 | if(m_nSinglePane != SPLIT_PANE_NONE) 742 | return false; 743 | if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y)) 744 | return false; 745 | int xy = t_bVertical ? x : y; 746 | int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top; 747 | return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge)); 748 | } 749 | 750 | void DrawGhostBar() 751 | { 752 | RECT rect = { 0 }; 753 | if(GetSplitterBarRect(&rect)) 754 | { 755 | // convert client to window coordinates 756 | T* pT = static_cast(this); 757 | RECT rcWnd = { 0 }; 758 | pT->GetWindowRect(&rcWnd); 759 | ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2); 760 | ::OffsetRect(&rect, -rcWnd.left, -rcWnd.top); 761 | 762 | // invert the brush pattern (looks just like frame window sizing) 763 | CWindowDC dc(pT->m_hWnd); 764 | CBrush brush = CDCHandle::GetHalftoneBrush(); 765 | if(brush.m_hBrush != NULL) 766 | { 767 | CBrushHandle brushOld = dc.SelectBrush(brush); 768 | dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); 769 | dc.SelectBrush(brushOld); 770 | } 771 | } 772 | } 773 | 774 | void GetSystemSettings(bool bUpdate) 775 | { 776 | if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0) 777 | { 778 | #ifndef _WIN32_WCE 779 | m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME); 780 | #else // CE specific 781 | m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); 782 | #endif // _WIN32_WCE 783 | } 784 | 785 | T* pT = static_cast(this); 786 | if((pT->GetExStyle() & WS_EX_CLIENTEDGE)) 787 | { 788 | m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); 789 | m_cxyMin = 0; 790 | } 791 | else 792 | { 793 | m_cxyBarEdge = 0; 794 | m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); 795 | } 796 | 797 | #ifndef _WIN32_WCE 798 | ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0); 799 | #endif // !_WIN32_WCE 800 | 801 | if(bUpdate) 802 | UpdateSplitterLayout(); 803 | } 804 | 805 | bool IsProportional() const 806 | { 807 | return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); 808 | } 809 | 810 | void StoreProportionalPos() 811 | { 812 | int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); 813 | if(cxyTotal > 0) 814 | m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal); 815 | else 816 | m_nProportionalPos = 0; 817 | ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos); 818 | } 819 | 820 | void UpdateProportionalPos() 821 | { 822 | int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); 823 | if(cxyTotal > 0) 824 | { 825 | int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax); 826 | m_bUpdateProportionalPos = false; 827 | T* pT = static_cast(this); 828 | pT->SetSplitterPos(xyNewPos, false); 829 | } 830 | } 831 | 832 | bool IsRightAligned() const 833 | { 834 | return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); 835 | } 836 | 837 | void StoreRightAlignPos() 838 | { 839 | int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); 840 | if(cxyTotal > 0) 841 | m_nProportionalPos = cxyTotal - m_xySplitterPos; 842 | else 843 | m_nProportionalPos = 0; 844 | ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos); 845 | } 846 | 847 | void UpdateRightAlignPos() 848 | { 849 | int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); 850 | if(cxyTotal > 0) 851 | { 852 | m_bUpdateProportionalPos = false; 853 | T* pT = static_cast(this); 854 | pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false); 855 | } 856 | } 857 | 858 | bool IsInteractive() const 859 | { 860 | return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); 861 | } 862 | }; 863 | 864 | template HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL; 865 | 866 | 867 | /////////////////////////////////////////////////////////////////////////////// 868 | // CSplitterWindowImpl - Implements a splitter window 869 | 870 | template 871 | class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical > 872 | { 873 | public: 874 | DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) 875 | 876 | typedef CSplitterImpl< T , t_bVertical > _baseClass; 877 | 878 | BEGIN_MSG_MAP(CSplitterWindowImpl) 879 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 880 | MESSAGE_HANDLER(WM_SIZE, OnSize) 881 | CHAIN_MSG_MAP(_baseClass) 882 | FORWARD_NOTIFICATIONS() 883 | END_MSG_MAP() 884 | 885 | LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 886 | { 887 | // handled, no background painting needed 888 | return 1; 889 | } 890 | 891 | LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) 892 | { 893 | if(wParam != SIZE_MINIMIZED) 894 | SetSplitterRect(); 895 | 896 | bHandled = FALSE; 897 | return 1; 898 | } 899 | }; 900 | 901 | 902 | /////////////////////////////////////////////////////////////////////////////// 903 | // CSplitterWindow - Implements a splitter window to be used as is 904 | 905 | template 906 | class CSplitterWindowT : public CSplitterWindowImpl, t_bVertical> 907 | { 908 | public: 909 | DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) 910 | }; 911 | 912 | typedef CSplitterWindowT CSplitterWindow; 913 | typedef CSplitterWindowT CHorSplitterWindow; 914 | 915 | }; // namespace WTL 916 | 917 | #endif // __ATLSPLIT_H__ 918 | -------------------------------------------------------------------------------- /D/D/wtl/atlfind.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLFIND_H__ 13 | #define __ATLFIND_H__ 14 | 15 | #pragma once 16 | 17 | #ifdef _WIN32_WCE 18 | #error atlfind.h is not supported on Windows CE 19 | #endif 20 | 21 | #ifndef __ATLCTRLS_H__ 22 | #error atlfind.h requires atlctrls.h to be included first 23 | #endif 24 | 25 | #ifndef __ATLDLGS_H__ 26 | #error atlfind.h requires atldlgs.h to be included first 27 | #endif 28 | 29 | #if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__)) 30 | #error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING) 31 | #endif 32 | 33 | 34 | /////////////////////////////////////////////////////////////////////////////// 35 | // Classes in this file: 36 | // 37 | // CEditFindReplaceImplBase 38 | // CEditFindReplaceImpl 39 | // CRichEditFindReplaceImpl 40 | 41 | 42 | namespace WTL 43 | { 44 | 45 | /////////////////////////////////////////////////////////////////////////////// 46 | // CEditFindReplaceImplBase - Base class for mixin classes that 47 | // help implement Find/Replace for CEdit or CRichEditCtrl based window classes. 48 | 49 | template 50 | class CEditFindReplaceImplBase 51 | { 52 | protected: 53 | // Typedefs 54 | typedef CEditFindReplaceImplBase thisClass; 55 | 56 | // Data members 57 | TFindReplaceDialog* m_pFindReplaceDialog; 58 | _CSTRING_NS::CString m_sFindNext, m_sReplaceWith; 59 | BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown; 60 | LONG m_nInitialSearchPos; 61 | HCURSOR m_hOldCursor; 62 | 63 | // Enumerations 64 | enum TranslationTextItem 65 | { 66 | eText_OnReplaceAllMessage = 0, 67 | eText_OnReplaceAllTitle = 1, 68 | eText_OnTextNotFoundMessage = 2, 69 | eText_OnTextNotFoundTitle = 3 70 | }; 71 | 72 | public: 73 | // Constructors 74 | CEditFindReplaceImplBase() : 75 | m_pFindReplaceDialog(NULL), 76 | m_bFindOnly(TRUE), 77 | m_bFirstSearch(TRUE), 78 | m_bMatchCase(FALSE), 79 | m_bWholeWord(FALSE), 80 | m_bFindDown(TRUE), 81 | m_nInitialSearchPos(0), 82 | m_hOldCursor(NULL) 83 | { 84 | } 85 | 86 | // Message Handlers 87 | BEGIN_MSG_MAP(thisClass) 88 | ALT_MSG_MAP(1) 89 | MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 90 | MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd) 91 | COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind) 92 | COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat) 93 | COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace) 94 | END_MSG_MAP() 95 | 96 | LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 97 | { 98 | if(m_pFindReplaceDialog != NULL) 99 | { 100 | m_pFindReplaceDialog->SendMessage(WM_CLOSE); 101 | ATLASSERT(m_pFindReplaceDialog == NULL); 102 | } 103 | 104 | bHandled = FALSE; 105 | return 0; 106 | } 107 | 108 | LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) 109 | { 110 | T* pT = static_cast(this); 111 | 112 | TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam); 113 | if(pDialog == NULL) 114 | { 115 | ATLASSERT(FALSE); 116 | ::MessageBeep(MB_ICONERROR); 117 | return 1; 118 | } 119 | ATLASSERT(pDialog == m_pFindReplaceDialog); 120 | 121 | LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam; 122 | if((m_pFindReplaceDialog != NULL) && (findReplace != NULL)) 123 | { 124 | if(pDialog->FindNext()) 125 | { 126 | pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(), 127 | pDialog->MatchCase(), pDialog->MatchWholeWord()); 128 | } 129 | else if(pDialog->ReplaceCurrent()) 130 | { 131 | pT->OnReplaceSel(pDialog->GetFindString(), 132 | pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(), 133 | pDialog->GetReplaceString()); 134 | } 135 | else if(pDialog->ReplaceAll()) 136 | { 137 | pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(), 138 | pDialog->MatchCase(), pDialog->MatchWholeWord()); 139 | } 140 | else if(pDialog->IsTerminating()) 141 | { 142 | // Dialog is going away (but hasn't gone away yet) 143 | // OnFinalMessage will "delete this" 144 | pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog); 145 | m_pFindReplaceDialog = NULL; 146 | } 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 153 | { 154 | T* pT = static_cast(this); 155 | pT->FindReplace(TRUE); 156 | 157 | return 0; 158 | } 159 | 160 | LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 161 | { 162 | T* pT = static_cast(this); 163 | 164 | // If the user is holding down SHIFT when hitting F3, we'll 165 | // search in reverse. Otherwise, we'll search forward. 166 | // (be sure to have an accelerator mapped to ID_EDIT_REPEAT 167 | // for both F3 and Shift+F3) 168 | m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); 169 | 170 | if(m_sFindNext.IsEmpty()) 171 | { 172 | pT->FindReplace(TRUE); 173 | } 174 | else 175 | { 176 | if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) 177 | pT->TextNotFound(m_sFindNext); 178 | } 179 | 180 | return 0; 181 | } 182 | 183 | LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled) 184 | { 185 | T* pT = static_cast(this); 186 | 187 | DWORD style = pT->GetStyle(); 188 | if((style & ES_READONLY) != ES_READONLY) 189 | { 190 | pT->FindReplace(FALSE); 191 | } 192 | else 193 | { 194 | // Don't allow replace when the edit control is read only 195 | bHandled = FALSE; 196 | } 197 | 198 | return 0; 199 | } 200 | 201 | // Operations (overrideable) 202 | TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace 203 | LPCTSTR lpszFindWhat, 204 | LPCTSTR lpszReplaceWith = NULL, 205 | DWORD dwFlags = FR_DOWN, 206 | HWND hWndParent = NULL) 207 | { 208 | // You can override all of this in a derived class 209 | 210 | TFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog(); 211 | if(findReplaceDialog == NULL) 212 | { 213 | ::MessageBeep(MB_ICONHAND); 214 | } 215 | else 216 | { 217 | HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly, 218 | lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent); 219 | if(hWndFindReplace == NULL) 220 | { 221 | delete findReplaceDialog; 222 | findReplaceDialog = NULL; 223 | } 224 | else 225 | { 226 | findReplaceDialog->SetActiveWindow(); 227 | findReplaceDialog->ShowWindow(SW_SHOW); 228 | } 229 | } 230 | 231 | return findReplaceDialog; 232 | } 233 | 234 | void AdjustDialogPosition(HWND hWndDialog) 235 | { 236 | ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog)); 237 | 238 | T* pT = static_cast(this); 239 | LONG nStartChar = 0, nEndChar = 0; 240 | // Send EM_GETSEL so we can use both Edit and RichEdit 241 | // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) 242 | ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); 243 | POINT point = pT->PosFromChar(nStartChar); 244 | ::ClientToScreen(pT->GetParent(), &point); 245 | CRect rect; 246 | ::GetWindowRect(hWndDialog, &rect); 247 | if(rect.PtInRect(point)) 248 | { 249 | if(point.y > rect.Height()) 250 | { 251 | rect.OffsetRect(0, point.y - rect.bottom - 20); 252 | } 253 | else 254 | { 255 | int nVertExt = GetSystemMetrics(SM_CYSCREEN); 256 | if(point.y + rect.Height() < nVertExt) 257 | rect.OffsetRect(0, 40 + point.y - rect.top); 258 | } 259 | 260 | ::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE); 261 | } 262 | } 263 | 264 | DWORD GetFindReplaceDialogFlags(void) const 265 | { 266 | DWORD dwFlags = 0; 267 | 268 | if(m_bFindDown) 269 | dwFlags |= FR_DOWN; 270 | if(m_bMatchCase) 271 | dwFlags |= FR_MATCHCASE; 272 | if(m_bWholeWord) 273 | dwFlags |= FR_WHOLEWORD; 274 | 275 | return dwFlags; 276 | } 277 | 278 | void FindReplace(BOOL bFindOnly) 279 | { 280 | T* pT = static_cast(this); 281 | m_bFirstSearch = TRUE; 282 | if(m_pFindReplaceDialog != NULL) 283 | { 284 | if(m_bFindOnly == bFindOnly) 285 | { 286 | m_pFindReplaceDialog->SetActiveWindow(); 287 | m_pFindReplaceDialog->ShowWindow(SW_SHOW); 288 | return; 289 | } 290 | else 291 | { 292 | m_pFindReplaceDialog->SendMessage(WM_CLOSE); 293 | ATLASSERT(m_pFindReplaceDialog == NULL); 294 | } 295 | } 296 | 297 | ATLASSERT(m_pFindReplaceDialog == NULL); 298 | 299 | _CSTRING_NS::CString findNext; 300 | pT->GetSelText(findNext); 301 | // if selection is empty or spans multiple lines use old find text 302 | if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1)) 303 | findNext = m_sFindNext; 304 | _CSTRING_NS::CString replaceWith = m_sReplaceWith; 305 | DWORD dwFlags = pT->GetFindReplaceDialogFlags(); 306 | 307 | m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly, 308 | findNext, replaceWith, dwFlags, pT->operator HWND()); 309 | ATLASSERT(m_pFindReplaceDialog != NULL); 310 | if(m_pFindReplaceDialog != NULL) 311 | m_bFindOnly = bFindOnly; 312 | } 313 | 314 | BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/) 315 | { 316 | T* pT = static_cast(this); 317 | 318 | // check length first 319 | size_t nLen = lstrlen(lpszCompare); 320 | LONG nStartChar = 0, nEndChar = 0; 321 | // Send EM_GETSEL so we can use both Edit and RichEdit 322 | // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) 323 | ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); 324 | if(nLen != (size_t)(nEndChar - nStartChar)) 325 | return FALSE; 326 | 327 | // length is the same, check contents 328 | _CSTRING_NS::CString selectedText; 329 | pT->GetSelText(selectedText); 330 | 331 | return (bMatchCase && selectedText.Compare(lpszCompare) == 0) || 332 | (!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0); 333 | } 334 | 335 | void TextNotFound(LPCTSTR lpszFind) 336 | { 337 | T* pT = static_cast(this); 338 | m_bFirstSearch = TRUE; 339 | pT->OnTextNotFound(lpszFind); 340 | } 341 | 342 | _CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const 343 | { 344 | _CSTRING_NS::CString text; 345 | switch(eItem) 346 | { 347 | case eText_OnReplaceAllMessage: 348 | text = _T("Replaced %d occurances of \"%s\" with \"%s\""); 349 | break; 350 | case eText_OnReplaceAllTitle: 351 | text = _T("Replace All"); 352 | break; 353 | case eText_OnTextNotFoundMessage: 354 | text = _T("Unable to find the text \"%s\""); 355 | break; 356 | case eText_OnTextNotFoundTitle: 357 | text = _T("Text not found"); 358 | break; 359 | } 360 | 361 | return text; 362 | } 363 | 364 | // Overrideable Handlers 365 | void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord) 366 | { 367 | T* pT = static_cast(this); 368 | 369 | m_sFindNext = lpszFind; 370 | m_bMatchCase = bMatchCase; 371 | m_bWholeWord = bWholeWord; 372 | m_bFindDown = bFindDown; 373 | 374 | if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) 375 | pT->TextNotFound(m_sFindNext); 376 | else 377 | pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); 378 | } 379 | 380 | void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace) 381 | { 382 | T* pT = static_cast(this); 383 | 384 | m_sFindNext = lpszFind; 385 | m_sReplaceWith = lpszReplace; 386 | m_bMatchCase = bMatchCase; 387 | m_bWholeWord = bWholeWord; 388 | m_bFindDown = bFindDown; 389 | 390 | if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) 391 | pT->ReplaceSel(m_sReplaceWith); 392 | 393 | if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) 394 | pT->TextNotFound(m_sFindNext); 395 | else 396 | pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); 397 | } 398 | 399 | void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord) 400 | { 401 | T* pT = static_cast(this); 402 | 403 | m_sFindNext = lpszFind; 404 | m_sReplaceWith = lpszReplace; 405 | m_bMatchCase = bMatchCase; 406 | m_bWholeWord = bWholeWord; 407 | m_bFindDown = TRUE; 408 | 409 | // no selection or different than what looking for 410 | if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) 411 | { 412 | if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) 413 | { 414 | pT->TextNotFound(m_sFindNext); 415 | return; 416 | } 417 | } 418 | 419 | pT->OnReplaceAllCoreBegin(); 420 | 421 | int replaceCount=0; 422 | do 423 | { 424 | ++replaceCount; 425 | pT->ReplaceSel(m_sReplaceWith); 426 | } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)); 427 | 428 | pT->OnReplaceAllCoreEnd(replaceCount); 429 | } 430 | 431 | void OnReplaceAllCoreBegin() 432 | { 433 | T* pT = static_cast(this); 434 | 435 | m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); 436 | 437 | pT->HideSelection(TRUE, FALSE); 438 | 439 | } 440 | 441 | void OnReplaceAllCoreEnd(int replaceCount) 442 | { 443 | T* pT = static_cast(this); 444 | pT->HideSelection(FALSE, FALSE); 445 | 446 | ::SetCursor(m_hOldCursor); 447 | 448 | _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage); 449 | if(message.GetLength() > 0) 450 | { 451 | _CSTRING_NS::CString formattedMessage; 452 | formattedMessage.Format(message, 453 | replaceCount, m_sFindNext, m_sReplaceWith); 454 | if(m_pFindReplaceDialog != NULL) 455 | { 456 | m_pFindReplaceDialog->MessageBox(formattedMessage, 457 | pT->GetTranslationText(eText_OnReplaceAllTitle), 458 | MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); 459 | } 460 | else 461 | { 462 | pT->MessageBox(formattedMessage, 463 | pT->GetTranslationText(eText_OnReplaceAllTitle), 464 | MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); 465 | } 466 | } 467 | } 468 | 469 | void OnTextNotFound(LPCTSTR lpszFind) 470 | { 471 | T* pT = static_cast(this); 472 | _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage); 473 | if(message.GetLength() > 0) 474 | { 475 | _CSTRING_NS::CString formattedMessage; 476 | formattedMessage.Format(message, lpszFind); 477 | if(m_pFindReplaceDialog != NULL) 478 | { 479 | m_pFindReplaceDialog->MessageBox(formattedMessage, 480 | pT->GetTranslationText(eText_OnTextNotFoundTitle), 481 | MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); 482 | } 483 | else 484 | { 485 | pT->MessageBox(formattedMessage, 486 | pT->GetTranslationText(eText_OnTextNotFoundTitle), 487 | MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); 488 | } 489 | } 490 | else 491 | { 492 | ::MessageBeep(MB_ICONHAND); 493 | } 494 | } 495 | 496 | void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/) 497 | { 498 | } 499 | }; 500 | 501 | 502 | /////////////////////////////////////////////////////////////////////////////// 503 | // CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit 504 | // based window classes. 505 | 506 | // Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit. 507 | // Example: 508 | // class CMyEdit : public CWindowImpl, 509 | // public CEditFindReplaceImpl 510 | // { 511 | // public: 512 | // BEGIN_MSG_MAP(CMyEdit) 513 | // // your handlers... 514 | // CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl, 1) 515 | // END_MSG_MAP() 516 | // // other stuff... 517 | // }; 518 | 519 | template 520 | class CEditFindReplaceImpl : public CEditFindReplaceImplBase 521 | { 522 | protected: 523 | typedef CEditFindReplaceImpl thisClass; 524 | typedef CEditFindReplaceImplBase baseClass; 525 | 526 | // Data members 527 | LPTSTR m_pShadowBuffer; // Special shadow buffer only used in some cases. 528 | UINT m_nShadowSize; 529 | int m_bShadowBufferNeeded; // TRUE, FALSE, < 0 => Need to check 530 | 531 | public: 532 | // Constructors 533 | CEditFindReplaceImpl() : 534 | m_pShadowBuffer(NULL), 535 | m_nShadowSize(0), 536 | m_bShadowBufferNeeded(-1) 537 | { 538 | } 539 | 540 | virtual ~CEditFindReplaceImpl() 541 | { 542 | if(m_pShadowBuffer != NULL) 543 | { 544 | delete [] m_pShadowBuffer; 545 | m_pShadowBuffer = NULL; 546 | } 547 | } 548 | 549 | // Message Handlers 550 | BEGIN_MSG_MAP(thisClass) 551 | ALT_MSG_MAP(1) 552 | CHAIN_MSG_MAP_ALT(baseClass, 1) 553 | END_MSG_MAP() 554 | 555 | // Operations 556 | // Supported only for RichEdit, so this does nothing for Edit 557 | void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE) 558 | { 559 | } 560 | 561 | // Operations (overrideable) 562 | BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) 563 | { 564 | T* pT = static_cast(this); 565 | 566 | ATLASSERT(lpszFind != NULL); 567 | ATLASSERT(*lpszFind != _T('\0')); 568 | 569 | UINT nLen = pT->GetBufferLength(); 570 | int nStartChar = 0, nEndChar = 0; 571 | pT->GetSel(nStartChar, nEndChar); 572 | UINT nStart = nStartChar; 573 | int iDir = bFindDown ? +1 : -1; 574 | 575 | // can't find a match before the first character 576 | if(nStart == 0 && iDir < 0) 577 | return FALSE; 578 | 579 | LPCTSTR lpszText = pT->LockBuffer(); 580 | 581 | bool isDBCS = false; 582 | #ifdef _MBCS 583 | CPINFO info = { 0 }; 584 | ::GetCPInfo(::GetOEMCP(), &info); 585 | isDBCS = (info.MaxCharSize > 1); 586 | #endif 587 | 588 | if(iDir < 0) 589 | { 590 | // always go back one for search backwards 591 | nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); 592 | } 593 | else if(nStartChar != nEndChar && pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord)) 594 | { 595 | // easy to go backward/forward with SBCS 596 | #ifndef _UNICODE 597 | if(::IsDBCSLeadByte(lpszText[nStart])) 598 | nStart++; 599 | #endif 600 | nStart += iDir; 601 | } 602 | 603 | // handle search with nStart past end of buffer 604 | UINT nLenFind = ::lstrlen(lpszFind); 605 | if(nStart + nLenFind - 1 >= nLen) 606 | { 607 | if(iDir < 0 && nLen >= nLenFind) 608 | { 609 | if(isDBCS) 610 | { 611 | // walk back to previous character n times 612 | nStart = nLen; 613 | int n = nLenFind; 614 | while(n--) 615 | { 616 | nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); 617 | } 618 | } 619 | else 620 | { 621 | // single-byte character set is easy and fast 622 | nStart = nLen - nLenFind; 623 | } 624 | ATLASSERT(nStart + nLenFind - 1 <= nLen); 625 | } 626 | else 627 | { 628 | pT->UnlockBuffer(); 629 | return FALSE; 630 | } 631 | } 632 | 633 | // start the search at nStart 634 | LPCTSTR lpsz = lpszText + nStart; 635 | typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2); 636 | CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi; 637 | 638 | if(isDBCS) 639 | { 640 | // double-byte string search 641 | LPCTSTR lpszStop = NULL; 642 | if(iDir > 0) 643 | { 644 | // start at current and find _first_ occurrance 645 | lpszStop = lpszText + nLen - nLenFind + 1; 646 | } 647 | else 648 | { 649 | // start at top and find _last_ occurrance 650 | lpszStop = lpsz; 651 | lpsz = lpszText; 652 | } 653 | 654 | LPCTSTR lpszFound = NULL; 655 | while(lpsz <= lpszStop) 656 | { 657 | #ifndef _UNICODE 658 | if(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1]))) 659 | #else 660 | if(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1])) 661 | #endif 662 | { 663 | LPTSTR lpch = (LPTSTR)(lpsz + nLenFind); 664 | TCHAR chSave = *lpch; 665 | *lpch = _T('\0'); 666 | int nResult = (*pfnCompare)(lpsz, lpszFind); 667 | *lpch = chSave; 668 | if(nResult == 0) 669 | { 670 | lpszFound = lpsz; 671 | if(iDir > 0) 672 | break; 673 | } 674 | } 675 | lpsz = ::CharNext(lpsz); 676 | } 677 | pT->UnlockBuffer(); 678 | 679 | if(lpszFound != NULL) 680 | { 681 | int n = (int)(lpszFound - lpszText); 682 | pT->SetSel(n, n + nLenFind); 683 | return TRUE; 684 | } 685 | } 686 | else 687 | { 688 | // single-byte string search 689 | UINT nCompare; 690 | if(iDir < 0) 691 | nCompare = (UINT)(lpsz - lpszText) + 1; 692 | else 693 | nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1; 694 | 695 | while(nCompare > 0) 696 | { 697 | ATLASSERT(lpsz >= lpszText); 698 | ATLASSERT(lpsz + nLenFind - 1 <= lpszText + nLen - 1); 699 | 700 | LPSTR lpch = (LPSTR)(lpsz + nLenFind); 701 | char chSave = *lpch; 702 | *lpch = '\0'; 703 | int nResult = (*pfnCompare)(lpsz, lpszFind); 704 | *lpch = chSave; 705 | if(nResult == 0) 706 | { 707 | pT->UnlockBuffer(); 708 | int n = (int)(lpsz - lpszText); 709 | pT->SetSel(n, n + nLenFind); 710 | return TRUE; 711 | } 712 | 713 | // restore character at end of search 714 | *lpch = chSave; 715 | 716 | // move on to next substring 717 | nCompare--; 718 | lpsz += iDir; 719 | } 720 | pT->UnlockBuffer(); 721 | } 722 | 723 | return FALSE; 724 | } 725 | 726 | LPCTSTR LockBuffer() const 727 | { 728 | const T* pT = static_cast(this); 729 | 730 | ATLASSERT(pT->m_hWnd != NULL); 731 | 732 | BOOL useShadowBuffer = pT->UseShadowBuffer(); 733 | if(useShadowBuffer) 734 | { 735 | if(m_pShadowBuffer == NULL || pT->GetModify()) 736 | { 737 | ATLASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0); 738 | UINT nSize = pT->GetWindowTextLength() + 1; 739 | if(nSize > m_nShadowSize) 740 | { 741 | // need more room for shadow buffer 742 | T* pThisNoConst = const_cast(pT); 743 | delete[] m_pShadowBuffer; 744 | pThisNoConst->m_pShadowBuffer = NULL; 745 | pThisNoConst->m_nShadowSize = 0; 746 | pThisNoConst->m_pShadowBuffer = new TCHAR[nSize]; 747 | pThisNoConst->m_nShadowSize = nSize; 748 | } 749 | 750 | // update the shadow buffer with GetWindowText 751 | ATLASSERT(m_nShadowSize >= nSize); 752 | ATLASSERT(m_pShadowBuffer != NULL); 753 | pT->GetWindowText(m_pShadowBuffer, nSize); 754 | } 755 | 756 | return m_pShadowBuffer; 757 | } 758 | 759 | HLOCAL hLocal = pT->GetHandle(); 760 | ATLASSERT(hLocal != NULL); 761 | LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal); 762 | ATLASSERT(lpszText != NULL); 763 | 764 | return lpszText; 765 | } 766 | 767 | void UnlockBuffer() const 768 | { 769 | const T* pT = static_cast(this); 770 | 771 | ATLASSERT(pT->m_hWnd != NULL); 772 | 773 | BOOL useShadowBuffer = pT->UseShadowBuffer(); 774 | if(!useShadowBuffer) 775 | { 776 | HLOCAL hLocal = pT->GetHandle(); 777 | ATLASSERT(hLocal != NULL); 778 | ::LocalUnlock(hLocal); 779 | } 780 | } 781 | 782 | UINT GetBufferLength() const 783 | { 784 | const T* pT = static_cast(this); 785 | 786 | ATLASSERT(pT->m_hWnd != NULL); 787 | UINT nLen = 0; 788 | LPCTSTR lpszText = pT->LockBuffer(); 789 | if(lpszText != NULL) 790 | nLen = ::lstrlen(lpszText); 791 | pT->UnlockBuffer(); 792 | 793 | return nLen; 794 | } 795 | 796 | LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const 797 | { 798 | LPCTSTR lpsz = lpszText + nIndex; 799 | LPCTSTR lpszStop = lpszText + nLen; 800 | while(lpsz < lpszStop && *lpsz != _T('\r')) 801 | ++lpsz; 802 | return LONG(lpsz - lpszText); 803 | } 804 | 805 | LONG GetSelText(_CSTRING_NS::CString& strText) const 806 | { 807 | const T* pT = static_cast(this); 808 | 809 | int nStartChar = 0, nEndChar = 0; 810 | pT->GetSel(nStartChar, nEndChar); 811 | ATLASSERT((UINT)nEndChar <= pT->GetBufferLength()); 812 | LPCTSTR lpszText = pT->LockBuffer(); 813 | LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar; 814 | SecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR)); 815 | strText.ReleaseBuffer(nLen); 816 | pT->UnlockBuffer(); 817 | 818 | return nLen; 819 | } 820 | 821 | BOOL UseShadowBuffer(void) const 822 | { 823 | const T* pT = static_cast(this); 824 | 825 | if(pT->m_bShadowBufferNeeded < 0) 826 | { 827 | T* pThisNoConst = const_cast(pT); 828 | 829 | OSVERSIONINFO ovi = { 0 }; 830 | ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 831 | ::GetVersionEx(&ovi); 832 | 833 | bool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); 834 | if(bWin9x) 835 | { 836 | // Windows 95, 98, ME 837 | // Under Win9x, it is necessary to maintain a shadow buffer. 838 | // It is only updated when the control contents have been changed. 839 | pThisNoConst->m_bShadowBufferNeeded = TRUE; 840 | } 841 | else 842 | { 843 | // Windows NT, 2000, XP, etc. 844 | pThisNoConst->m_bShadowBufferNeeded = FALSE; 845 | 846 | #ifndef _UNICODE 847 | // On Windows XP (or later), if common controls version 6 is in use 848 | // (such as via theming), then EM_GETHANDLE will always return a UNICODE string. 849 | // If theming is enabled and Common Controls version 6 is in use, 850 | // you're really not suppose to superclass or subclass common controls 851 | // with an ANSI windows procedure (so its best to only theme if you use UNICODE). 852 | // Using a shadow buffer uses GetWindowText instead, so it solves 853 | // this problem for us (although it makes it a little less efficient). 854 | 855 | if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) 856 | { 857 | // We use DLLVERSIONINFO_private so we don't have to depend on shlwapi.h 858 | typedef struct _DLLVERSIONINFO_private 859 | { 860 | DWORD cbSize; 861 | DWORD dwMajorVersion; 862 | DWORD dwMinorVersion; 863 | DWORD dwBuildNumber; 864 | DWORD dwPlatformID; 865 | } DLLVERSIONINFO_private; 866 | 867 | HMODULE hModule = ::LoadLibrary("comctl32.dll"); 868 | if(hModule != NULL) 869 | { 870 | typedef HRESULT (CALLBACK *LPFN_DllGetVersion)(DLLVERSIONINFO_private *); 871 | LPFN_DllGetVersion fnDllGetVersion = (LPFN_DllGetVersion)::GetProcAddress(hModule, "DllGetVersion"); 872 | if(fnDllGetVersion != NULL) 873 | { 874 | DLLVERSIONINFO_private version = { 0 }; 875 | version.cbSize = sizeof(DLLVERSIONINFO_private); 876 | if(SUCCEEDED(fnDllGetVersion(&version))) 877 | { 878 | if(version.dwMajorVersion >= 6) 879 | { 880 | pThisNoConst->m_bShadowBufferNeeded = TRUE; 881 | 882 | ATLTRACE2(atlTraceUI, 0, _T("Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later (likely through a manifest file).\r\n")); 883 | ATLTRACE2(atlTraceUI, 0, _T("If you use common controls version 6 or later, you should only do so for UNICODE builds.\r\n")); 884 | } 885 | } 886 | } 887 | 888 | ::FreeLibrary(hModule); 889 | hModule = NULL; 890 | } 891 | } 892 | #endif // !_UNICODE 893 | } 894 | } 895 | 896 | return (pT->m_bShadowBufferNeeded != FALSE); 897 | } 898 | }; 899 | 900 | 901 | /////////////////////////////////////////////////////////////////////////////// 902 | // CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl 903 | // based window classes. 904 | 905 | // Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl. 906 | // Example: 907 | // class CMyRichEdit : public CWindowImpl, 908 | // public CRichEditFindReplaceImpl 909 | // { 910 | // public: 911 | // BEGIN_MSG_MAP(CMyRichEdit) 912 | // // your handlers... 913 | // CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl, 1) 914 | // END_MSG_MAP() 915 | // // other stuff... 916 | // }; 917 | 918 | template 919 | class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase 920 | { 921 | protected: 922 | typedef CRichEditFindReplaceImpl thisClass; 923 | typedef CEditFindReplaceImplBase baseClass; 924 | 925 | public: 926 | BEGIN_MSG_MAP(thisClass) 927 | ALT_MSG_MAP(1) 928 | CHAIN_MSG_MAP_ALT(baseClass, 1) 929 | END_MSG_MAP() 930 | 931 | // Operations (overrideable) 932 | BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) 933 | { 934 | T* pT = static_cast(this); 935 | 936 | ATLASSERT(lpszFind != NULL); 937 | FINDTEXTEX ft = { 0 }; 938 | 939 | pT->GetSel(ft.chrg); 940 | if(m_bFirstSearch) 941 | { 942 | if(bFindDown) 943 | m_nInitialSearchPos = ft.chrg.cpMin; 944 | else 945 | m_nInitialSearchPos = ft.chrg.cpMax; 946 | m_bFirstSearch = FALSE; 947 | } 948 | 949 | #if (_RICHEDIT_VER >= 0x0200) 950 | ft.lpstrText = (LPTSTR)lpszFind; 951 | #else // !(_RICHEDIT_VER >= 0x0200) 952 | USES_CONVERSION; 953 | ft.lpstrText = T2A((LPTSTR)lpszFind); 954 | #endif // !(_RICHEDIT_VER >= 0x0200) 955 | 956 | if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection 957 | { 958 | if(bFindDown) 959 | { 960 | ft.chrg.cpMin++; 961 | } 962 | else 963 | { 964 | // won't wraparound backwards 965 | ft.chrg.cpMin = max(ft.chrg.cpMin, 0); 966 | } 967 | } 968 | 969 | DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0; 970 | dwFlags |= bWholeWord ? FR_WHOLEWORD : 0; 971 | 972 | ft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos; 973 | 974 | if(bFindDown) 975 | { 976 | if(m_nInitialSearchPos >= 0) 977 | ft.chrg.cpMax = pT->GetTextLength(); 978 | 979 | dwFlags |= FR_DOWN; 980 | ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin); 981 | } 982 | else 983 | { 984 | if(m_nInitialSearchPos >= 0) 985 | ft.chrg.cpMax = 0; 986 | 987 | dwFlags &= ~FR_DOWN; 988 | ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin); 989 | } 990 | 991 | BOOL bRet = FALSE; 992 | 993 | if(pT->FindAndSelect(dwFlags, ft) != -1) 994 | { 995 | bRet = TRUE; // we found the text 996 | } 997 | else if(m_nInitialSearchPos > 0) 998 | { 999 | // if the original starting point was not the beginning 1000 | // of the buffer and we haven't already been here 1001 | if(bFindDown) 1002 | { 1003 | ft.chrg.cpMin = 0; 1004 | ft.chrg.cpMax = m_nInitialSearchPos; 1005 | } 1006 | else 1007 | { 1008 | ft.chrg.cpMin = pT->GetTextLength(); 1009 | ft.chrg.cpMax = m_nInitialSearchPos; 1010 | } 1011 | m_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength(); 1012 | 1013 | bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE; 1014 | } 1015 | 1016 | return bRet; 1017 | } 1018 | 1019 | long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft) 1020 | { 1021 | T* pT = static_cast(this); 1022 | LONG index = pT->FindText(dwFlags, ft); 1023 | if(index != -1) // i.e. we found something 1024 | pT->SetSel(ft.chrgText); 1025 | 1026 | return index; 1027 | } 1028 | }; 1029 | 1030 | }; // namespace WTL 1031 | 1032 | #endif // __ATLFIND_H__ 1033 | -------------------------------------------------------------------------------- /D/D/wtl/atlprint.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLPRINT_H__ 13 | #define __ATLPRINT_H__ 14 | 15 | #pragma once 16 | 17 | #ifdef _WIN32_WCE 18 | #error atlprint.h is not supported on Windows CE 19 | #endif 20 | 21 | #ifndef __ATLAPP_H__ 22 | #error atlprint.h requires atlapp.h to be included first 23 | #endif 24 | 25 | #ifndef __ATLWIN_H__ 26 | #error atlprint.h requires atlwin.h to be included first 27 | #endif 28 | 29 | 30 | /////////////////////////////////////////////////////////////////////////////// 31 | // Classes in this file: 32 | // 33 | // CPrinterInfo 34 | // CPrinterT 35 | // CDevModeT 36 | // CPrinterDC 37 | // CPrintJobInfo 38 | // CPrintJob 39 | // CPrintPreview 40 | // CPrintPreviewWindowImpl 41 | // CPrintPreviewWindow 42 | // CZoomPrintPreviewWindowImpl 43 | // CZoomPrintPreviewWindow 44 | 45 | namespace WTL 46 | { 47 | 48 | /////////////////////////////////////////////////////////////////////////////// 49 | // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures 50 | // and provided by ::GetPrinter. 51 | 52 | template 53 | class _printer_info 54 | { 55 | public: 56 | typedef void infotype; 57 | }; 58 | 59 | template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; }; 60 | template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; }; 61 | template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; }; 62 | template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; }; 63 | template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; }; 64 | template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; }; 65 | template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; }; 66 | // these are not in the old (vc6.0) headers 67 | #ifdef _ATL_USE_NEW_PRINTER_INFO 68 | template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; }; 69 | template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; }; 70 | #endif // _ATL_USE_NEW_PRINTER_INFO 71 | 72 | 73 | template 74 | class CPrinterInfo 75 | { 76 | public: 77 | // Data members 78 | typename _printer_info::infotype* m_pi; 79 | 80 | // Constructor/destructor 81 | CPrinterInfo() : m_pi(NULL) 82 | { } 83 | 84 | CPrinterInfo(HANDLE hPrinter) : m_pi(NULL) 85 | { 86 | GetPrinterInfo(hPrinter); 87 | } 88 | 89 | ~CPrinterInfo() 90 | { 91 | Cleanup(); 92 | } 93 | 94 | // Operations 95 | bool GetPrinterInfo(HANDLE hPrinter) 96 | { 97 | Cleanup(); 98 | return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo); 99 | } 100 | 101 | // Implementation 102 | void Cleanup() 103 | { 104 | delete [] (BYTE*)m_pi; 105 | m_pi = NULL; 106 | } 107 | 108 | static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex) 109 | { 110 | ATLASSERT(pi != NULL); 111 | DWORD dw = 0; 112 | BYTE* pb = NULL; 113 | ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw); 114 | if (dw > 0) 115 | { 116 | ATLTRY(pb = new BYTE[dw]); 117 | if (pb != NULL) 118 | { 119 | memset(pb, 0, dw); 120 | DWORD dwNew; 121 | if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew)) 122 | { 123 | delete [] pb; 124 | pb = NULL; 125 | } 126 | } 127 | } 128 | *pi = pb; 129 | return (pb != NULL); 130 | } 131 | }; 132 | 133 | 134 | /////////////////////////////////////////////////////////////////////////////// 135 | // CPrinter - Wrapper class for a HANDLE to a printer 136 | 137 | template 138 | class CPrinterT 139 | { 140 | public: 141 | // Data members 142 | HANDLE m_hPrinter; 143 | 144 | // Constructor/destructor 145 | CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter) 146 | { } 147 | 148 | ~CPrinterT() 149 | { 150 | ClosePrinter(); 151 | } 152 | 153 | // Operations 154 | CPrinterT& operator =(HANDLE hPrinter) 155 | { 156 | if (hPrinter != m_hPrinter) 157 | { 158 | ClosePrinter(); 159 | m_hPrinter = hPrinter; 160 | } 161 | return *this; 162 | } 163 | 164 | bool IsNull() const { return (m_hPrinter == NULL); } 165 | 166 | bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL) 167 | { 168 | bool b = false; 169 | DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames); 170 | if (pdn != NULL) 171 | { 172 | LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset; 173 | b = OpenPrinter(lpszPrinterName, pDevMode); 174 | ::GlobalUnlock(hDevNames); 175 | } 176 | return b; 177 | } 178 | 179 | bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL) 180 | { 181 | ClosePrinter(); 182 | PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; 183 | ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); 184 | 185 | return (m_hPrinter != NULL); 186 | } 187 | 188 | bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs) 189 | { 190 | ClosePrinter(); 191 | ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs); 192 | return (m_hPrinter != NULL); 193 | } 194 | 195 | bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL) 196 | { 197 | ClosePrinter(); 198 | const int cchBuff = 512; 199 | TCHAR buffer[cchBuff]; 200 | buffer[0] = 0; 201 | ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff); 202 | int nLen = lstrlen(buffer); 203 | if (nLen != 0) 204 | { 205 | LPTSTR lpsz = buffer; 206 | while (*lpsz) 207 | { 208 | if (*lpsz == _T(',')) 209 | { 210 | *lpsz = 0; 211 | break; 212 | } 213 | lpsz = CharNext(lpsz); 214 | } 215 | PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; 216 | ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); 217 | } 218 | return m_hPrinter != NULL; 219 | } 220 | 221 | void ClosePrinter() 222 | { 223 | if (m_hPrinter != NULL) 224 | { 225 | if (t_bManaged) 226 | ::ClosePrinter(m_hPrinter); 227 | m_hPrinter = NULL; 228 | } 229 | } 230 | 231 | bool PrinterProperties(HWND hWnd = NULL) 232 | { 233 | if (hWnd == NULL) 234 | hWnd = ::GetActiveWindow(); 235 | return !!::PrinterProperties(hWnd, m_hPrinter); 236 | } 237 | 238 | HANDLE CopyToHDEVNAMES() const 239 | { 240 | HANDLE h = NULL; 241 | CPrinterInfo<5> pinfon5; 242 | CPrinterInfo<2> pinfon2; 243 | LPTSTR lpszPrinterName = NULL; 244 | // Some printers fail for PRINTER_INFO_5 in some situations 245 | if (pinfon5.GetPrinterInfo(m_hPrinter)) 246 | lpszPrinterName = pinfon5.m_pi->pPrinterName; 247 | else if (pinfon2.GetPrinterInfo(m_hPrinter)) 248 | lpszPrinterName = pinfon2.m_pi->pPrinterName; 249 | if (lpszPrinterName != NULL) 250 | { 251 | int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR); 252 | h = ::GlobalAlloc(GMEM_MOVEABLE, nLen); 253 | BYTE* pv = (BYTE*)::GlobalLock(h); 254 | DEVNAMES* pdev = (DEVNAMES*)pv; 255 | if (pv != NULL) 256 | { 257 | memset(pv, 0, nLen); 258 | pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR); 259 | pv = pv + sizeof(DEVNAMES); // now points to end 260 | SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName); 261 | ::GlobalUnlock(h); 262 | } 263 | } 264 | return h; 265 | } 266 | 267 | HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const 268 | { 269 | CPrinterInfo<5> pinfo5; 270 | CPrinterInfo<2> pinfo2; 271 | HDC hDC = NULL; 272 | LPTSTR lpszPrinterName = NULL; 273 | // Some printers fail for PRINTER_INFO_5 in some situations 274 | if (pinfo5.GetPrinterInfo(m_hPrinter)) 275 | lpszPrinterName = pinfo5.m_pi->pPrinterName; 276 | else if (pinfo2.GetPrinterInfo(m_hPrinter)) 277 | lpszPrinterName = pinfo2.m_pi->pPrinterName; 278 | if (lpszPrinterName != NULL) 279 | hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm); 280 | return hDC; 281 | } 282 | 283 | HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const 284 | { 285 | CPrinterInfo<5> pinfo5; 286 | CPrinterInfo<2> pinfo2; 287 | HDC hDC = NULL; 288 | LPTSTR lpszPrinterName = NULL; 289 | // Some printers fail for PRINTER_INFO_5 in some situations 290 | if (pinfo5.GetPrinterInfo(m_hPrinter)) 291 | lpszPrinterName = pinfo5.m_pi->pPrinterName; 292 | else if (pinfo2.GetPrinterInfo(m_hPrinter)) 293 | lpszPrinterName = pinfo2.m_pi->pPrinterName; 294 | if (lpszPrinterName != NULL) 295 | hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm); 296 | return hDC; 297 | } 298 | 299 | void Attach(HANDLE hPrinter) 300 | { 301 | ClosePrinter(); 302 | m_hPrinter = hPrinter; 303 | } 304 | 305 | HANDLE Detach() 306 | { 307 | HANDLE hPrinter = m_hPrinter; 308 | m_hPrinter = NULL; 309 | return hPrinter; 310 | } 311 | 312 | operator HANDLE() const { return m_hPrinter; } 313 | }; 314 | 315 | typedef CPrinterT CPrinterHandle; 316 | typedef CPrinterT CPrinter; 317 | 318 | 319 | /////////////////////////////////////////////////////////////////////////////// 320 | // CDevMode - Wrapper class for DEVMODE 321 | 322 | template 323 | class CDevModeT 324 | { 325 | public: 326 | // Data members 327 | HANDLE m_hDevMode; 328 | DEVMODE* m_pDevMode; 329 | 330 | // Constructor/destructor 331 | CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode) 332 | { 333 | m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; 334 | } 335 | 336 | ~CDevModeT() 337 | { 338 | Cleanup(); 339 | } 340 | 341 | // Operations 342 | CDevModeT& operator =(HANDLE hDevMode) 343 | { 344 | Attach(hDevMode); 345 | return *this; 346 | } 347 | 348 | void Attach(HANDLE hDevModeNew) 349 | { 350 | Cleanup(); 351 | m_hDevMode = hDevModeNew; 352 | m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; 353 | } 354 | 355 | HANDLE Detach() 356 | { 357 | if (m_hDevMode != NULL) 358 | ::GlobalUnlock(m_hDevMode); 359 | HANDLE hDevMode = m_hDevMode; 360 | m_hDevMode = NULL; 361 | return hDevMode; 362 | } 363 | 364 | bool IsNull() const { return (m_hDevMode == NULL); } 365 | 366 | bool CopyFromPrinter(HANDLE hPrinter) 367 | { 368 | CPrinterInfo<2> pinfo; 369 | bool b = pinfo.GetPrinterInfo(hPrinter); 370 | if (b) 371 | b = CopyFromDEVMODE(pinfo.m_pi->pDevMode); 372 | return b; 373 | } 374 | 375 | bool CopyFromDEVMODE(const DEVMODE* pdm) 376 | { 377 | if (pdm == NULL) 378 | return false; 379 | int nSize = pdm->dmSize + pdm->dmDriverExtra; 380 | HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); 381 | if (h != NULL) 382 | { 383 | void* p = ::GlobalLock(h); 384 | SecureHelper::memcpy_x(p, nSize, pdm, nSize); 385 | ::GlobalUnlock(h); 386 | } 387 | Attach(h); 388 | return (h != NULL); 389 | } 390 | 391 | bool CopyFromHDEVMODE(HANDLE hdm) 392 | { 393 | bool b = false; 394 | if (hdm != NULL) 395 | { 396 | DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm); 397 | b = CopyFromDEVMODE(pdm); 398 | ::GlobalUnlock(hdm); 399 | } 400 | return b; 401 | } 402 | 403 | HANDLE CopyToHDEVMODE() 404 | { 405 | if ((m_hDevMode == NULL) || (m_pDevMode == NULL)) 406 | return NULL; 407 | int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra; 408 | HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); 409 | if (h != NULL) 410 | { 411 | void* p = ::GlobalLock(h); 412 | SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize); 413 | ::GlobalUnlock(h); 414 | } 415 | return h; 416 | } 417 | 418 | // If this devmode was for another printer, this will create a new devmode 419 | // based on the existing devmode, but retargeted at the new printer 420 | bool UpdateForNewPrinter(HANDLE hPrinter) 421 | { 422 | bool bRet = false; 423 | LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0); 424 | CTempBuffer buff; 425 | DEVMODE* pdm = buff.AllocateBytes(nLen); 426 | if(pdm != NULL) 427 | { 428 | memset(pdm, 0, nLen); 429 | LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); 430 | if (l == IDOK) 431 | bRet = CopyFromDEVMODE(pdm); 432 | } 433 | 434 | return bRet; 435 | } 436 | 437 | bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL) 438 | { 439 | CPrinterInfo<1> pi; 440 | pi.GetPrinterInfo(hPrinter); 441 | if (hWnd == NULL) 442 | hWnd = ::GetActiveWindow(); 443 | 444 | bool bRet = false; 445 | LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0); 446 | CTempBuffer buff; 447 | DEVMODE* pdm = buff.AllocateBytes(nLen); 448 | if(pdm != NULL) 449 | { 450 | memset(pdm, 0, nLen); 451 | LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT); 452 | if (l == IDOK) 453 | bRet = CopyFromDEVMODE(pdm); 454 | } 455 | 456 | return bRet; 457 | } 458 | 459 | operator HANDLE() const { return m_hDevMode; } 460 | 461 | operator DEVMODE*() const { return m_pDevMode; } 462 | 463 | // Implementation 464 | void Cleanup() 465 | { 466 | if (m_hDevMode != NULL) 467 | { 468 | ::GlobalUnlock(m_hDevMode); 469 | if(t_bManaged) 470 | ::GlobalFree(m_hDevMode); 471 | m_hDevMode = NULL; 472 | } 473 | } 474 | }; 475 | 476 | typedef CDevModeT CDevModeHandle; 477 | typedef CDevModeT CDevMode; 478 | 479 | 480 | /////////////////////////////////////////////////////////////////////////////// 481 | // CPrinterDC 482 | 483 | class CPrinterDC : public CDC 484 | { 485 | public: 486 | // Constructors/destructor 487 | CPrinterDC() 488 | { 489 | CPrinter printer; 490 | printer.OpenDefaultPrinter(); 491 | Attach(printer.CreatePrinterDC()); 492 | ATLASSERT(m_hDC != NULL); 493 | } 494 | 495 | CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL) 496 | { 497 | CPrinterHandle p; 498 | p.Attach(hPrinter); 499 | Attach(p.CreatePrinterDC(pdm)); 500 | ATLASSERT(m_hDC != NULL); 501 | } 502 | 503 | ~CPrinterDC() 504 | { 505 | DeleteDC(); 506 | } 507 | }; 508 | 509 | 510 | /////////////////////////////////////////////////////////////////////////////// 511 | // CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc) 512 | // Handles aborting, background printing 513 | 514 | // Defines callbacks used by CPrintJob (not a COM interface) 515 | class ATL_NO_VTABLE IPrintJobInfo 516 | { 517 | public: 518 | virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc. 519 | virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc. 520 | virtual void PrePrintPage(UINT nPage, HDC hDC) = 0; 521 | virtual bool PrintPage(UINT nPage, HDC hDC) = 0; 522 | virtual void PostPrintPage(UINT nPage, HDC hDC) = 0; 523 | // If you want per page devmodes, return the DEVMODE* to use for nPage. 524 | // You can optimize by only returning a new DEVMODE* when it is different 525 | // from the one for nLastPage, otherwise return NULL. 526 | // When nLastPage==0, the current DEVMODE* will be the default passed to 527 | // StartPrintJob. 528 | // Note: During print preview, nLastPage will always be "0". 529 | virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0; 530 | virtual bool IsValidPage(UINT nPage) = 0; 531 | }; 532 | 533 | // Provides a default implementatin for IPrintJobInfo 534 | // Typically, MI'd into a document or view class 535 | class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo 536 | { 537 | public: 538 | virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc 539 | { 540 | } 541 | 542 | virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc 543 | { 544 | } 545 | 546 | virtual void PrePrintPage(UINT /*nPage*/, HDC hDC) 547 | { 548 | m_nPJState = ::SaveDC(hDC); 549 | } 550 | 551 | virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0; 552 | 553 | virtual void PostPrintPage(UINT /*nPage*/, HDC hDC) 554 | { 555 | RestoreDC(hDC, m_nPJState); 556 | } 557 | 558 | virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/) 559 | { 560 | return NULL; 561 | } 562 | 563 | virtual bool IsValidPage(UINT /*nPage*/) 564 | { 565 | return true; 566 | } 567 | 568 | // Implementation - data 569 | int m_nPJState; 570 | }; 571 | 572 | 573 | class CPrintJob 574 | { 575 | public: 576 | // Data members 577 | CPrinterHandle m_printer; 578 | IPrintJobInfo* m_pInfo; 579 | DEVMODE* m_pDefDevMode; 580 | DOCINFO m_docinfo; 581 | int m_nJobID; 582 | bool m_bCancel; 583 | bool m_bComplete; 584 | unsigned long m_nStartPage; 585 | unsigned long m_nEndPage; 586 | 587 | // Constructor/destructor 588 | CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true) 589 | { } 590 | 591 | ~CPrintJob() 592 | { 593 | ATLASSERT(IsJobComplete()); // premature destruction? 594 | } 595 | 596 | // Operations 597 | bool IsJobComplete() const 598 | { 599 | return m_bComplete; 600 | } 601 | 602 | bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode, 603 | IPrintJobInfo* pInfo, LPCTSTR lpszDocName, 604 | unsigned long nStartPage, unsigned long nEndPage, 605 | bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL) 606 | { 607 | ATLASSERT(m_bComplete); // previous job not done yet? 608 | if (pInfo == NULL) 609 | return false; 610 | 611 | memset(&m_docinfo, 0, sizeof(m_docinfo)); 612 | m_docinfo.cbSize = sizeof(m_docinfo); 613 | m_docinfo.lpszDocName = lpszDocName; 614 | m_pInfo = pInfo; 615 | m_nStartPage = nStartPage; 616 | m_nEndPage = nEndPage; 617 | m_printer.Attach(hPrinter); 618 | m_pDefDevMode = pDefaultDevMode; 619 | m_bComplete = false; 620 | 621 | if(bPrintToFile) 622 | m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:"); 623 | 624 | if (!bBackground) 625 | { 626 | m_bComplete = true; 627 | return StartHelper(); 628 | } 629 | 630 | // Create a thread and return 631 | DWORD dwThreadID = 0; 632 | #if !defined(_ATL_MIN_CRT) && defined(_MT) 633 | HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID); 634 | #else 635 | HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID); 636 | #endif 637 | if (hThread == NULL) 638 | return false; 639 | 640 | ::CloseHandle(hThread); 641 | 642 | return true; 643 | } 644 | 645 | // Implementation 646 | static DWORD WINAPI StartProc(void* p) 647 | { 648 | CPrintJob* pThis = (CPrintJob*)p; 649 | pThis->StartHelper(); 650 | pThis->m_bComplete = true; 651 | return 0; 652 | } 653 | 654 | bool StartHelper() 655 | { 656 | CDC dcPrinter; 657 | dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode)); 658 | if (dcPrinter.IsNull()) 659 | return false; 660 | 661 | m_nJobID = ::StartDoc(dcPrinter, &m_docinfo); 662 | if (m_nJobID <= 0) 663 | return false; 664 | 665 | m_pInfo->BeginPrintJob(dcPrinter); 666 | 667 | // print all the pages now 668 | unsigned long nLastPage = 0; 669 | for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++) 670 | { 671 | if (!m_pInfo->IsValidPage(nPage)) 672 | break; 673 | DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage); 674 | if (pdm != NULL) 675 | dcPrinter.ResetDC(pdm); 676 | dcPrinter.StartPage(); 677 | m_pInfo->PrePrintPage(nPage, dcPrinter); 678 | if (!m_pInfo->PrintPage(nPage, dcPrinter)) 679 | m_bCancel = true; 680 | m_pInfo->PostPrintPage(nPage, dcPrinter); 681 | dcPrinter.EndPage(); 682 | if (m_bCancel) 683 | break; 684 | nLastPage = nPage; 685 | } 686 | 687 | m_pInfo->EndPrintJob(dcPrinter, m_bCancel); 688 | if (m_bCancel) 689 | ::AbortDoc(dcPrinter); 690 | else 691 | ::EndDoc(dcPrinter); 692 | m_nJobID = 0; 693 | return true; 694 | } 695 | 696 | // Cancels a print job. Can be called asynchronously. 697 | void CancelPrintJob() 698 | { 699 | m_bCancel = true; 700 | } 701 | }; 702 | 703 | 704 | /////////////////////////////////////////////////////////////////////////////// 705 | // CPrintPreview - Adds print preview support to an existing window 706 | 707 | class CPrintPreview 708 | { 709 | public: 710 | // Data members 711 | IPrintJobInfo* m_pInfo; 712 | CPrinterHandle m_printer; 713 | CEnhMetaFile m_meta; 714 | DEVMODE* m_pDefDevMode; 715 | DEVMODE* m_pCurDevMode; 716 | SIZE m_sizeCurPhysOffset; 717 | 718 | // Constructor 719 | CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL) 720 | { 721 | m_sizeCurPhysOffset.cx = 0; 722 | m_sizeCurPhysOffset.cy = 0; 723 | } 724 | 725 | // Operations 726 | void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji) 727 | { 728 | m_printer.Attach(hPrinter); 729 | m_pDefDevMode = pDefaultDevMode; 730 | m_pInfo = pji; 731 | m_nCurPage = 0; 732 | m_pCurDevMode = NULL; 733 | } 734 | 735 | void SetEnhMetaFile(HENHMETAFILE hEMF) 736 | { 737 | m_meta = hEMF; 738 | } 739 | 740 | void SetPage(int nPage) 741 | { 742 | if (!m_pInfo->IsValidPage(nPage)) 743 | return; 744 | m_nCurPage = nPage; 745 | m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage); 746 | if (m_pCurDevMode == NULL) 747 | m_pCurDevMode = m_pDefDevMode; 748 | CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode); 749 | 750 | int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); 751 | int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); 752 | int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX); 753 | int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY); 754 | 755 | RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) }; 756 | 757 | m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX); 758 | m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY); 759 | 760 | CEnhMetaFileDC dcMeta(dcPrinter, &rcMM); 761 | m_pInfo->PrePrintPage(nPage, dcMeta); 762 | m_pInfo->PrintPage(nPage, dcMeta); 763 | m_pInfo->PostPrintPage(nPage, dcMeta); 764 | m_meta.Attach(dcMeta.Close()); 765 | } 766 | 767 | void GetPageRect(RECT& rc, LPRECT prc) 768 | { 769 | int x1 = rc.right-rc.left; 770 | int y1 = rc.bottom - rc.top; 771 | if ((x1 < 0) || (y1 < 0)) 772 | return; 773 | 774 | CEnhMetaFileInfo emfinfo(m_meta); 775 | ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); 776 | 777 | // Compute whether we are OK vertically or horizontally 778 | int x2 = pmh->szlDevice.cx; 779 | int y2 = pmh->szlDevice.cy; 780 | int y1p = MulDiv(x1, y2, x2); 781 | int x1p = MulDiv(y1, x2, y2); 782 | ATLASSERT((x1p <= x1) || (y1p <= y1)); 783 | if (x1p <= x1) 784 | { 785 | prc->left = rc.left + (x1 - x1p) / 2; 786 | prc->right = prc->left + x1p; 787 | prc->top = rc.top; 788 | prc->bottom = rc.bottom; 789 | } 790 | else 791 | { 792 | prc->left = rc.left; 793 | prc->right = rc.right; 794 | prc->top = rc.top + (y1 - y1p) / 2; 795 | prc->bottom = prc->top + y1p; 796 | } 797 | } 798 | 799 | // Painting helpers 800 | void DoPaint(CDCHandle dc) 801 | { 802 | // this one is not used 803 | } 804 | 805 | void DoPaint(CDCHandle dc, RECT& rc) 806 | { 807 | CEnhMetaFileInfo emfinfo(m_meta); 808 | ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); 809 | int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); 810 | int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); 811 | 812 | dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); 813 | dc.PlayMetaFile(m_meta, &rc); 814 | } 815 | 816 | // Implementation - data 817 | int m_nCurPage; 818 | }; 819 | 820 | 821 | /////////////////////////////////////////////////////////////////////////////// 822 | // CPrintPreviewWindow - Implements a print preview window 823 | 824 | template 825 | class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl, public CPrintPreview 826 | { 827 | public: 828 | DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1) 829 | 830 | enum { m_cxOffset = 10, m_cyOffset = 10 }; 831 | 832 | // Constructor 833 | CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0) 834 | { } 835 | 836 | // Operations 837 | void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, 838 | IPrintJobInfo* pji, int nMinPage, int nMaxPage) 839 | { 840 | CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji); 841 | m_nMinPage = nMinPage; 842 | m_nMaxPage = nMaxPage; 843 | } 844 | 845 | bool NextPage() 846 | { 847 | if (m_nCurPage == m_nMaxPage) 848 | return false; 849 | SetPage(m_nCurPage + 1); 850 | Invalidate(); 851 | return true; 852 | } 853 | 854 | bool PrevPage() 855 | { 856 | if (m_nCurPage == m_nMinPage) 857 | return false; 858 | if (m_nCurPage == 0) 859 | return false; 860 | SetPage(m_nCurPage - 1); 861 | Invalidate(); 862 | return true; 863 | } 864 | 865 | // Message map and handlers 866 | BEGIN_MSG_MAP(CPrintPreviewWindowImpl) 867 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 868 | MESSAGE_HANDLER(WM_PAINT, OnPaint) 869 | MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) 870 | END_MSG_MAP() 871 | 872 | LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 873 | { 874 | return 1; // no need for the background 875 | } 876 | 877 | LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 878 | { 879 | T* pT = static_cast(this); 880 | RECT rc = { 0 }; 881 | 882 | if(wParam != NULL) 883 | { 884 | pT->DoPrePaint((HDC)wParam, rc); 885 | pT->DoPaint((HDC)wParam, rc); 886 | } 887 | else 888 | { 889 | CPaintDC dc(m_hWnd); 890 | pT->DoPrePaint(dc.m_hDC, rc); 891 | pT->DoPaint(dc.m_hDC, rc); 892 | } 893 | 894 | return 0; 895 | } 896 | 897 | // Painting helper 898 | void DoPrePaint(CDCHandle dc, RECT& rc) 899 | { 900 | RECT rcClient = { 0 }; 901 | GetClientRect(&rcClient); 902 | RECT rcArea = rcClient; 903 | T* pT = static_cast(this); 904 | pT; // avoid level 4 warning 905 | ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); 906 | if (rcArea.left > rcArea.right) 907 | rcArea.right = rcArea.left; 908 | if (rcArea.top > rcArea.bottom) 909 | rcArea.bottom = rcArea.top; 910 | GetPageRect(rcArea, &rc); 911 | CRgn rgn1, rgn2; 912 | rgn1.CreateRectRgnIndirect(&rc); 913 | rgn2.CreateRectRgnIndirect(&rcClient); 914 | rgn2.CombineRgn(rgn1, RGN_DIFF); 915 | dc.SelectClipRgn(rgn2); 916 | dc.FillRect(&rcClient, COLOR_BTNSHADOW); 917 | dc.SelectClipRgn(NULL); 918 | dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); 919 | } 920 | 921 | // Implementation - data 922 | int m_nMinPage; 923 | int m_nMaxPage; 924 | }; 925 | 926 | 927 | class CPrintPreviewWindow : public CPrintPreviewWindowImpl 928 | { 929 | public: 930 | DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) 931 | }; 932 | 933 | 934 | /////////////////////////////////////////////////////////////////////////////// 935 | // CZoomPrintPreviewWindowImpl - Implements print preview window with zooming 936 | 937 | #ifdef __ATLSCRL_H__ 938 | 939 | template 940 | class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > 941 | { 942 | public: 943 | bool m_bSized; 944 | 945 | CZoomPrintPreviewWindowImpl() 946 | { 947 | SetScrollExtendedStyle(SCRL_DISABLENOSCROLL); 948 | InitZoom(); 949 | } 950 | 951 | // should be called to reset data members before recreating window 952 | void InitZoom() 953 | { 954 | m_bSized = false; 955 | m_nZoomMode = ZOOMMODE_OFF; 956 | m_fZoomScaleMin = 1.0; 957 | m_fZoomScale = 1.0; 958 | } 959 | 960 | BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl) 961 | MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) 962 | MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) 963 | MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) 964 | MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) 965 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) 966 | MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) 967 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) 968 | MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) 969 | MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) 970 | MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) 971 | MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) 972 | MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) 973 | MESSAGE_HANDLER(WM_SIZE, OnSize) 974 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 975 | MESSAGE_HANDLER(WM_PAINT, OnPaint) 976 | MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) 977 | ALT_MSG_MAP(1) 978 | COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) 979 | COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) 980 | COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) 981 | COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) 982 | COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) 983 | COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) 984 | COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) 985 | COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) 986 | COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) 987 | COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) 988 | COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) 989 | COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) 990 | END_MSG_MAP() 991 | 992 | LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 993 | { 994 | SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; 995 | POINT ptOffset = m_ptOffset; 996 | SIZE sizeAll = m_sizeAll; 997 | SetScrollSize(sizeClient); 998 | if(sizeAll.cx > 0) 999 | ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx); 1000 | if(sizeAll.cy > 0) 1001 | ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy); 1002 | SetScrollOffset(ptOffset); 1003 | CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled); 1004 | if(!m_bSized) 1005 | { 1006 | m_bSized = true; 1007 | T* pT = static_cast(this); 1008 | pT->ShowScrollBar(SB_HORZ, TRUE); 1009 | pT->ShowScrollBar(SB_VERT, TRUE); 1010 | } 1011 | return 0; 1012 | } 1013 | 1014 | LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 1015 | { 1016 | return 1; 1017 | } 1018 | 1019 | LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 1020 | { 1021 | T* pT = static_cast(this); 1022 | RECT rc = { 0 }; 1023 | 1024 | if(wParam != NULL) 1025 | { 1026 | CDCHandle dc = (HDC)wParam; 1027 | int nMapModeSav = dc.GetMapMode(); 1028 | dc.SetMapMode(MM_ANISOTROPIC); 1029 | SIZE szWindowExt = { 0, 0 }; 1030 | dc.SetWindowExt(m_sizeLogAll, &szWindowExt); 1031 | SIZE szViewportExt = { 0, 0 }; 1032 | dc.SetViewportExt(m_sizeAll, &szViewportExt); 1033 | POINT ptViewportOrg = { 0, 0 }; 1034 | dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); 1035 | 1036 | pT->DoPrePaint(dc, rc); 1037 | pT->DoPaint(dc, rc); 1038 | 1039 | dc.SetMapMode(nMapModeSav); 1040 | dc.SetWindowExt(szWindowExt); 1041 | dc.SetViewportExt(szViewportExt); 1042 | dc.SetViewportOrg(ptViewportOrg); 1043 | } 1044 | else 1045 | { 1046 | CPaintDC dc(pT->m_hWnd); 1047 | pT->PrepareDC(dc.m_hDC); 1048 | pT->DoPrePaint(dc.m_hDC, rc); 1049 | pT->DoPaint(dc.m_hDC, rc); 1050 | } 1051 | 1052 | return 0; 1053 | } 1054 | 1055 | // Painting helpers 1056 | void DoPaint(CDCHandle dc) 1057 | { 1058 | // this one is not used 1059 | } 1060 | 1061 | void DoPrePaint(CDCHandle dc, RECT& rc) 1062 | { 1063 | RECT rcClient; 1064 | GetClientRect(&rcClient); 1065 | RECT rcArea = rcClient; 1066 | T* pT = static_cast(this); 1067 | pT; // avoid level 4 warning 1068 | ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); 1069 | if (rcArea.left > rcArea.right) 1070 | rcArea.right = rcArea.left; 1071 | if (rcArea.top > rcArea.bottom) 1072 | rcArea.bottom = rcArea.top; 1073 | GetPageRect(rcArea, &rc); 1074 | HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); 1075 | dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY); 1076 | dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY); 1077 | dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY); 1078 | dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY); 1079 | dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH)); 1080 | dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY); 1081 | dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW)); 1082 | dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY); 1083 | dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY); 1084 | dc.SelectBrush(hbrOld); 1085 | } 1086 | 1087 | void DoPaint(CDCHandle dc, RECT& rc) 1088 | { 1089 | CEnhMetaFileInfo emfinfo(m_meta); 1090 | ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); 1091 | int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); 1092 | int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); 1093 | 1094 | dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); 1095 | dc.PlayMetaFile(m_meta, &rc); 1096 | } 1097 | }; 1098 | 1099 | class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl 1100 | { 1101 | public: 1102 | DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) 1103 | }; 1104 | 1105 | #endif // __ATLSCRL_H__ 1106 | 1107 | }; // namespace WTL 1108 | 1109 | #endif // __ATLPRINT_H__ 1110 | -------------------------------------------------------------------------------- /D/D/wtl/atltheme.h: -------------------------------------------------------------------------------- 1 | // Windows Template Library - WTL version 8.1 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 | // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) 7 | // which can be found in the file CPL.TXT at the root of this distribution. 8 | // By using this software in any fashion, you are agreeing to be bound by 9 | // the terms of this license. You must not remove this notice, or 10 | // any other, from this software. 11 | 12 | #ifndef __ATLTHEME_H__ 13 | #define __ATLTHEME_H__ 14 | 15 | #pragma once 16 | 17 | #ifdef _WIN32_WCE 18 | #error atltheme.h is not supported on Windows CE 19 | #endif 20 | 21 | #ifndef __ATLAPP_H__ 22 | #error atltheme.h requires atlapp.h to be included first 23 | #endif 24 | 25 | #ifndef __ATLWIN_H__ 26 | #error atltheme.h requires atlwin.h to be included first 27 | #endif 28 | 29 | #if (_WIN32_WINNT < 0x0501) 30 | #error atltheme.h requires _WIN32_WINNT >= 0x0501 31 | #endif // (_WIN32_WINNT < 0x0501) 32 | 33 | #if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)) 34 | #include 35 | #else 36 | #ifndef TMSCHEMA_H 37 | #include 38 | #endif 39 | #endif 40 | 41 | #ifndef _UXTHEME_H_ 42 | #include 43 | #endif 44 | #pragma comment(lib, "uxtheme.lib") 45 | 46 | // Note: To create an application that also runs on older versions of Windows, 47 | // use delay load of uxtheme.dll and ensure that no calls to the Theme API are 48 | // made if theming is not supported. It is enough to check if m_hTheme is NULL. 49 | // Example: 50 | // if(m_hTheme != NULL) 51 | // { 52 | // DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL); 53 | // DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect); 54 | // } 55 | // else 56 | // { 57 | // dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH); 58 | // dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); 59 | // } 60 | // 61 | // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, 62 | // and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the 63 | // project properties. 64 | #if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) 65 | #pragma comment(lib, "delayimp.lib") 66 | #pragma comment(linker, "/delayload:uxtheme.dll") 67 | #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) 68 | 69 | // Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h 70 | // is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE 71 | #ifndef _WTL_NEW_UXTHEME 72 | #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) 73 | #define _WTL_NEW_UXTHEME 74 | #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) 75 | #endif // _WTL_NEW_UXTHEME 76 | 77 | 78 | /////////////////////////////////////////////////////////////////////////////// 79 | // Classes in this file: 80 | // 81 | // CTheme 82 | // CThemeImpl 83 | // 84 | // CBufferedPaint 85 | // CBufferedPaintImpl 86 | // CBufferedPaintWindowImpl 87 | // CBufferedAnimation 88 | // CBufferedAnimationImpl 89 | // CBufferedAnimationWindowImpl 90 | // 91 | // Global functions: 92 | // AtlDrawThemeClientEdge() 93 | 94 | 95 | namespace WTL 96 | { 97 | 98 | /////////////////////////////////////////////////////////////////////////////// 99 | // CTheme - wrapper for theme handle 100 | 101 | class CTheme 102 | { 103 | public: 104 | // Data members 105 | HTHEME m_hTheme; 106 | static int m_nIsThemingSupported; 107 | 108 | // Constructor 109 | CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme) 110 | { 111 | IsThemingSupported(); 112 | } 113 | 114 | // Operators and helpers 115 | bool IsThemeNull() const 116 | { 117 | return (m_hTheme == NULL); 118 | } 119 | 120 | CTheme& operator =(HTHEME hTheme) 121 | { 122 | m_hTheme = hTheme; 123 | return *this; 124 | } 125 | 126 | operator HTHEME() const 127 | { 128 | return m_hTheme; 129 | } 130 | 131 | void Attach(HTHEME hTheme) 132 | { 133 | m_hTheme = hTheme; 134 | } 135 | 136 | HTHEME Detach() 137 | { 138 | HTHEME hTheme = m_hTheme; 139 | m_hTheme = NULL; 140 | return hTheme; 141 | } 142 | 143 | // Theme support helper 144 | static bool IsThemingSupported() 145 | { 146 | if(m_nIsThemingSupported == -1) 147 | { 148 | CStaticDataInitCriticalSectionLock lock; 149 | if(FAILED(lock.Lock())) 150 | { 151 | ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n")); 152 | ATLASSERT(FALSE); 153 | return false; 154 | } 155 | 156 | if(m_nIsThemingSupported == -1) 157 | { 158 | HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); 159 | m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0; 160 | if(hThemeDLL != NULL) 161 | ::FreeLibrary(hThemeDLL); 162 | } 163 | 164 | lock.Unlock(); 165 | } 166 | 167 | ATLASSERT(m_nIsThemingSupported != -1); 168 | return (m_nIsThemingSupported == 1); 169 | } 170 | 171 | // Operations and theme properties 172 | HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList) 173 | { 174 | if(!IsThemingSupported()) 175 | return NULL; 176 | 177 | ATLASSERT(m_hTheme == NULL); 178 | m_hTheme = ::OpenThemeData(hWnd, pszClassList); 179 | return m_hTheme; 180 | } 181 | 182 | HRESULT CloseThemeData() 183 | { 184 | HRESULT hRet = S_FALSE; 185 | if(m_hTheme != NULL) 186 | { 187 | hRet = ::CloseThemeData(m_hTheme); 188 | if(SUCCEEDED(hRet)) 189 | m_hTheme = NULL; 190 | } 191 | return hRet; 192 | } 193 | 194 | HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL) 195 | { 196 | ATLASSERT(m_hTheme != NULL); 197 | return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect); 198 | } 199 | 200 | HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL) 201 | { 202 | ATLASSERT(m_hTheme != NULL); 203 | return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions); 204 | } 205 | 206 | HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect) 207 | { 208 | ATLASSERT(m_hTheme != NULL); 209 | return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect); 210 | } 211 | 212 | HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const 213 | { 214 | ATLASSERT(m_hTheme != NULL); 215 | return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect); 216 | } 217 | 218 | HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const 219 | { 220 | ATLASSERT(m_hTheme != NULL); 221 | return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect); 222 | } 223 | 224 | HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const 225 | { 226 | ATLASSERT(m_hTheme != NULL); 227 | return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize); 228 | } 229 | 230 | HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const 231 | { 232 | ATLASSERT(m_hTheme != NULL); 233 | return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect); 234 | } 235 | 236 | HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const 237 | { 238 | ATLASSERT(m_hTheme != NULL); 239 | #ifdef _WTL_NEW_UXTHEME 240 | return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric); 241 | #else // !_WTL_NEW_UXTHEME 242 | // Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW 243 | return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric); 244 | #endif // !_WTL_NEW_UXTHEME 245 | } 246 | 247 | HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const 248 | { 249 | ATLASSERT(m_hTheme != NULL); 250 | return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion); 251 | } 252 | 253 | HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const 254 | { 255 | ATLASSERT(m_hTheme != NULL); 256 | return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode); 257 | } 258 | 259 | HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL) 260 | { 261 | ATLASSERT(m_hTheme != NULL); 262 | return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect); 263 | } 264 | 265 | HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex) 266 | { 267 | ATLASSERT(m_hTheme != NULL); 268 | return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex); 269 | } 270 | 271 | BOOL IsThemePartDefined(int nPartID, int nStateID) const 272 | { 273 | ATLASSERT(m_hTheme != NULL); 274 | return ::IsThemePartDefined(m_hTheme, nPartID, nStateID); 275 | } 276 | 277 | BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const 278 | { 279 | ATLASSERT(m_hTheme != NULL); 280 | return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID); 281 | } 282 | 283 | HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const 284 | { 285 | ATLASSERT(m_hTheme != NULL); 286 | return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor); 287 | } 288 | 289 | HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const 290 | { 291 | ATLASSERT(m_hTheme != NULL); 292 | return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal); 293 | } 294 | 295 | HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const 296 | { 297 | ATLASSERT(m_hTheme != NULL); 298 | return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars); 299 | } 300 | 301 | HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const 302 | { 303 | ATLASSERT(m_hTheme != NULL); 304 | return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal); 305 | } 306 | 307 | HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const 308 | { 309 | ATLASSERT(m_hTheme != NULL); 310 | return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal); 311 | } 312 | 313 | HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const 314 | { 315 | ATLASSERT(m_hTheme != NULL); 316 | return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal); 317 | } 318 | 319 | HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const 320 | { 321 | ATLASSERT(m_hTheme != NULL); 322 | return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint); 323 | } 324 | 325 | // deprecated 326 | HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const 327 | { 328 | ATLASSERT(m_hTheme != NULL); 329 | #ifdef _WTL_NEW_UXTHEME 330 | return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); 331 | #else // !_WTL_NEW_UXTHEME 332 | // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* 333 | return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); 334 | #endif // !_WTL_NEW_UXTHEME 335 | } 336 | 337 | HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const 338 | { 339 | ATLASSERT(m_hTheme != NULL); 340 | #ifdef _WTL_NEW_UXTHEME 341 | return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); 342 | #else // !_WTL_NEW_UXTHEME 343 | // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* 344 | return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); 345 | #endif // !_WTL_NEW_UXTHEME 346 | } 347 | 348 | HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const 349 | { 350 | ATLASSERT(m_hTheme != NULL); 351 | return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect); 352 | } 353 | 354 | HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const 355 | { 356 | ATLASSERT(m_hTheme != NULL); 357 | return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins); 358 | } 359 | 360 | HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const 361 | { 362 | ATLASSERT(m_hTheme != NULL); 363 | return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList); 364 | } 365 | 366 | HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const 367 | { 368 | ATLASSERT(m_hTheme != NULL); 369 | return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin); 370 | } 371 | 372 | HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const 373 | { 374 | ATLASSERT(m_hTheme != NULL); 375 | return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars); 376 | } 377 | 378 | COLORREF GetThemeSysColor(int nColorID) const 379 | { 380 | ATLASSERT(m_hTheme != NULL); 381 | return ::GetThemeSysColor(m_hTheme, nColorID); 382 | } 383 | 384 | HBRUSH GetThemeSysColorBrush(int nColorID) const 385 | { 386 | ATLASSERT(m_hTheme != NULL); 387 | return ::GetThemeSysColorBrush(m_hTheme, nColorID); 388 | } 389 | 390 | int GetThemeSysSize(int nSizeID) const 391 | { 392 | ATLASSERT(m_hTheme != NULL); 393 | return ::GetThemeSysSize(m_hTheme, nSizeID); 394 | } 395 | 396 | BOOL GetThemeSysBool(int nBoolID) const 397 | { 398 | ATLASSERT(m_hTheme != NULL); 399 | return ::GetThemeSysBool(m_hTheme, nBoolID); 400 | } 401 | 402 | HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const 403 | { 404 | ATLASSERT(m_hTheme != NULL); 405 | #ifdef _WTL_NEW_UXTHEME 406 | return ::GetThemeSysFont(m_hTheme, nFontID, plf); 407 | #else // !_WTL_NEW_UXTHEME 408 | // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* 409 | return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf); 410 | #endif // !_WTL_NEW_UXTHEME 411 | } 412 | 413 | HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const 414 | { 415 | ATLASSERT(m_hTheme != NULL); 416 | return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars); 417 | } 418 | 419 | HRESULT GetThemeSysInt(int nIntID, int* pnValue) const 420 | { 421 | ATLASSERT(m_hTheme != NULL); 422 | return ::GetThemeSysInt(m_hTheme, nIntID, pnValue); 423 | } 424 | 425 | #ifdef _WTL_NEW_UXTHEME 426 | HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags) 427 | { 428 | if(!IsThemingSupported()) 429 | return NULL; 430 | 431 | ATLASSERT(m_hTheme == NULL); 432 | m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags); 433 | return m_hTheme; 434 | } 435 | 436 | HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions) 437 | { 438 | ATLASSERT(m_hTheme != NULL); 439 | return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions); 440 | } 441 | 442 | HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration) 443 | { 444 | ATLASSERT(m_hTheme != NULL); 445 | return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration); 446 | } 447 | #endif // _WTL_NEW_UXTHEME 448 | 449 | #if (_WIN32_WINNT >= 0x0600) 450 | HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap) 451 | { 452 | ATLASSERT(m_hTheme != NULL); 453 | return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap); 454 | } 455 | 456 | HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance) 457 | { 458 | ATLASSERT(m_hTheme != NULL); 459 | return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance); 460 | } 461 | #endif // (_WIN32_WINNT >= 0x0600) 462 | }; 463 | 464 | __declspec(selectany) int CTheme::m_nIsThemingSupported = -1; 465 | 466 | 467 | /////////////////////////////////////////////////////////////////////////////// 468 | // CThemeImpl - theme support implementation 469 | 470 | // Derive from this class to implement window with theme support. 471 | // Example: 472 | // class CMyThemeWindow : public CWindowImpl, public CThemeImpl 473 | // { 474 | // ... 475 | // BEGIN_MSG_MAP(CMyThemeWindow) 476 | // CHAIN_MSG_MAP(CThemeImpl) 477 | // ... 478 | // END_MSG_MAP() 479 | // ... 480 | // }; 481 | // 482 | // If you set theme class list, the class will automaticaly open/close/reopen theme data. 483 | 484 | 485 | // Helper for drawing theme client edge 486 | inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0) 487 | { 488 | ATLASSERT(hTheme != NULL); 489 | ATLASSERT(::IsWindow(hWnd)); 490 | 491 | CWindowDC dc(hWnd); 492 | if(dc.IsNull()) 493 | return false; 494 | 495 | // Get border size 496 | int cxBorder = GetSystemMetrics(SM_CXBORDER); 497 | int cyBorder = GetSystemMetrics(SM_CYBORDER); 498 | if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder))) 499 | cyBorder = cxBorder; 500 | 501 | RECT rect; 502 | ::GetWindowRect(hWnd, &rect); 503 | 504 | // Remove the client edge from the update region 505 | int cxEdge = GetSystemMetrics(SM_CXEDGE); 506 | int cyEdge = GetSystemMetrics(SM_CYEDGE); 507 | ::InflateRect(&rect, -cxEdge, -cyEdge); 508 | CRgn rgn; 509 | rgn.CreateRectRgnIndirect(&rect); 510 | if(rgn.IsNull()) 511 | return false; 512 | 513 | if(hRgnUpdate != NULL) 514 | rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND); 515 | 516 | ::OffsetRect(&rect, -rect.left, -rect.top); 517 | 518 | ::OffsetRect(&rect, cxEdge, cyEdge); 519 | dc.ExcludeClipRect(&rect); 520 | ::InflateRect(&rect, cxEdge, cyEdge); 521 | 522 | ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL); 523 | 524 | // Use background brush too, since theme border might not cover everything 525 | if(cxBorder < cxEdge && cyBorder < cyEdge) 526 | { 527 | if(hBrush == NULL) 528 | // need conditional code because types don't match in winuser.h 529 | #ifdef _WIN64 530 | hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND); 531 | #else 532 | hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND)); 533 | #endif 534 | 535 | ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge); 536 | dc.FillRect(&rect, hBrush); 537 | } 538 | 539 | ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L); 540 | 541 | return true; 542 | } 543 | 544 | 545 | // Theme extended styles 546 | #define THEME_EX_3DCLIENTEDGE 0x00000001 547 | #define THEME_EX_THEMECLIENTEDGE 0x00000002 548 | 549 | template 550 | class CThemeImpl : public TBase 551 | { 552 | public: 553 | // Data members 554 | LPWSTR m_lpstrThemeClassList; 555 | DWORD m_dwExtendedStyle; // theme specific extended styles 556 | 557 | // Constructor & destructor 558 | CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0) 559 | { } 560 | 561 | ~CThemeImpl() 562 | { 563 | delete [] m_lpstrThemeClassList; 564 | } 565 | 566 | // Attributes 567 | bool SetThemeClassList(LPCWSTR lpstrThemeClassList) 568 | { 569 | if(m_lpstrThemeClassList != NULL) 570 | { 571 | delete [] m_lpstrThemeClassList; 572 | m_lpstrThemeClassList = NULL; 573 | } 574 | 575 | if(lpstrThemeClassList == NULL) 576 | return true; 577 | 578 | int cchLen = lstrlenW(lpstrThemeClassList) + 1; 579 | ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]); 580 | if(m_lpstrThemeClassList == NULL) 581 | return false; 582 | 583 | SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList); 584 | 585 | return true; 586 | } 587 | 588 | bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const 589 | { 590 | int cchLen = lstrlenW(m_lpstrThemeClassList) + 1; 591 | if(cchListBuffer < cchLen) 592 | return false; 593 | 594 | SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList); 595 | 596 | return true; 597 | } 598 | 599 | LPCWSTR GetThemeClassList() const 600 | { 601 | return m_lpstrThemeClassList; 602 | } 603 | 604 | DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) 605 | { 606 | DWORD dwPrevStyle = m_dwExtendedStyle; 607 | if(dwMask == 0) 608 | m_dwExtendedStyle = dwExtendedStyle; 609 | else 610 | m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); 611 | return dwPrevStyle; 612 | } 613 | 614 | DWORD GetThemeExtendedStyle() const 615 | { 616 | return m_dwExtendedStyle; 617 | } 618 | 619 | // Operations 620 | HTHEME OpenThemeData() 621 | { 622 | T* pT = static_cast(this); 623 | ATLASSERT(::IsWindow(pT->m_hWnd)); 624 | ATLASSERT(m_lpstrThemeClassList != NULL); 625 | if(m_lpstrThemeClassList == NULL) 626 | return NULL; 627 | CloseThemeData(); 628 | return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList); 629 | } 630 | 631 | HTHEME OpenThemeData(LPCWSTR pszClassList) 632 | { 633 | if(!SetThemeClassList(pszClassList)) 634 | return NULL; 635 | return OpenThemeData(); 636 | } 637 | 638 | HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList) 639 | { 640 | if(!IsThemingSupported()) 641 | return S_FALSE; 642 | 643 | T* pT = static_cast(this); 644 | ATLASSERT(::IsWindow(pT->m_hWnd)); 645 | return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList); 646 | } 647 | 648 | HTHEME GetWindowTheme() const 649 | { 650 | if(!IsThemingSupported()) 651 | return NULL; 652 | 653 | const T* pT = static_cast(this); 654 | ATLASSERT(::IsWindow(pT->m_hWnd)); 655 | return ::GetWindowTheme(pT->m_hWnd); 656 | } 657 | 658 | HRESULT EnableThemeDialogTexture(DWORD dwFlags) 659 | { 660 | if(!IsThemingSupported()) 661 | return S_FALSE; 662 | 663 | T* pT = static_cast(this); 664 | ATLASSERT(::IsWindow(pT->m_hWnd)); 665 | return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags); 666 | } 667 | 668 | BOOL IsThemeDialogTextureEnabled() const 669 | { 670 | if(!IsThemingSupported()) 671 | return FALSE; 672 | 673 | const T* pT = static_cast(this); 674 | ATLASSERT(::IsWindow(pT->m_hWnd)); 675 | return ::IsThemeDialogTextureEnabled(pT->m_hWnd); 676 | } 677 | 678 | HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL) 679 | { 680 | if(!IsThemingSupported()) 681 | return S_FALSE; 682 | 683 | T* pT = static_cast(this); 684 | ATLASSERT(::IsWindow(pT->m_hWnd)); 685 | #ifdef _WTL_NEW_UXTHEME 686 | return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect); 687 | #else 688 | return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect); 689 | #endif 690 | } 691 | 692 | #ifdef _WTL_NEW_UXTHEME 693 | HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute) 694 | { 695 | if(!IsThemingSupported()) 696 | return S_FALSE; 697 | 698 | T* pT = static_cast(this); 699 | ATLASSERT(::IsWindow(pT->m_hWnd)); 700 | return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute); 701 | } 702 | 703 | HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask) 704 | { 705 | if(!IsThemingSupported()) 706 | return S_FALSE; 707 | 708 | T* pT = static_cast(this); 709 | ATLASSERT(::IsWindow(pT->m_hWnd)); 710 | WTA_OPTIONS opt = { dwAttributes, dwMask }; 711 | return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt)); 712 | } 713 | 714 | HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL) 715 | { 716 | if(!IsThemingSupported()) 717 | return S_FALSE; 718 | 719 | T* pT = static_cast(this); 720 | ATLASSERT(::IsWindow(pT->m_hWnd)); 721 | return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect); 722 | } 723 | #endif // _WTL_NEW_UXTHEME 724 | 725 | // Message map and handlers 726 | // Note: If you handle any of these messages in your derived class, 727 | // it is better to put CHAIN_MSG_MAP at the start of your message map. 728 | BEGIN_MSG_MAP(CThemeImpl) 729 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 730 | MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 731 | MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 732 | MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) 733 | END_MSG_MAP() 734 | 735 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 736 | { 737 | if(m_lpstrThemeClassList != NULL) 738 | OpenThemeData(); 739 | bHandled = FALSE; 740 | return 1; 741 | } 742 | 743 | LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 744 | { 745 | CloseThemeData(); 746 | bHandled = FALSE; 747 | return 1; 748 | } 749 | 750 | LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 751 | { 752 | CloseThemeData(); 753 | if(m_lpstrThemeClassList != NULL) 754 | OpenThemeData(); 755 | bHandled = FALSE; 756 | return 1; 757 | } 758 | 759 | LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 760 | { 761 | T* pT = static_cast(this); 762 | ATLASSERT(::IsWindow(pT->m_hWnd)); 763 | LRESULT lRet = 0; 764 | bHandled = FALSE; 765 | if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)) 766 | { 767 | if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0) 768 | { 769 | lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam); 770 | bHandled = TRUE; 771 | } 772 | else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0)) 773 | { 774 | HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL; 775 | if(pT->DrawThemeClientEdge(hRgn)) 776 | bHandled = TRUE; 777 | } 778 | } 779 | return lRet; 780 | } 781 | 782 | // Drawing helper 783 | bool DrawThemeClientEdge(HRGN hRgnUpdate) 784 | { 785 | T* pT = static_cast(this); 786 | return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0); 787 | } 788 | }; 789 | 790 | /////////////////////////////////////////////////////////////////////////////// 791 | // Buffered Paint and Animation 792 | 793 | #ifdef _WTL_NEW_UXTHEME 794 | 795 | /////////////////////////////////////////////////////////////////////////////// 796 | // CBufferedPaintBase - Buffered Paint support for othe classes 797 | 798 | class CBufferedPaintBase 799 | { 800 | public: 801 | static int m_nIsBufferedPaintSupported; 802 | 803 | CBufferedPaintBase() 804 | { 805 | if(IsBufferedPaintSupported()) 806 | ATLVERIFY(SUCCEEDED(::BufferedPaintInit())); 807 | } 808 | 809 | ~CBufferedPaintBase() 810 | { 811 | if(IsBufferedPaintSupported()) 812 | ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit())); 813 | } 814 | 815 | static bool IsBufferedPaintSupported() 816 | { 817 | if(m_nIsBufferedPaintSupported == -1) 818 | { 819 | CStaticDataInitCriticalSectionLock lock; 820 | if(FAILED(lock.Lock())) 821 | { 822 | ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n")); 823 | ATLASSERT(FALSE); 824 | return false; 825 | } 826 | 827 | if(m_nIsBufferedPaintSupported == -1) 828 | m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0; 829 | 830 | lock.Unlock(); 831 | } 832 | 833 | ATLASSERT(m_nIsBufferedPaintSupported != -1); 834 | return (m_nIsBufferedPaintSupported == 1); 835 | } 836 | }; 837 | 838 | __declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1; 839 | 840 | 841 | /////////////////////////////////////////////////////////////////////////////// 842 | // CBufferedPaint - support for buffered paint functions 843 | 844 | class CBufferedPaint 845 | { 846 | public: 847 | HPAINTBUFFER m_hPaintBuffer; 848 | 849 | CBufferedPaint() : m_hPaintBuffer(NULL) 850 | { } 851 | 852 | ~CBufferedPaint() 853 | { 854 | ATLVERIFY(SUCCEEDED(End())); 855 | } 856 | 857 | bool IsNull() const 858 | { 859 | return (m_hPaintBuffer == NULL); 860 | } 861 | 862 | HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint) 863 | { 864 | ATLASSERT(m_hPaintBuffer == NULL); 865 | m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint); 866 | return m_hPaintBuffer; 867 | } 868 | 869 | HRESULT End(BOOL bUpdate = TRUE) 870 | { 871 | HRESULT hRet = S_FALSE; 872 | if(m_hPaintBuffer != NULL) 873 | { 874 | hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate); 875 | m_hPaintBuffer = NULL; 876 | } 877 | return hRet; 878 | } 879 | 880 | HRESULT GetTargetRect(LPRECT pRect) const 881 | { 882 | ATLASSERT(m_hPaintBuffer != NULL); 883 | return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect); 884 | } 885 | 886 | HDC GetTargetDC() const 887 | { 888 | ATLASSERT(m_hPaintBuffer != NULL); 889 | return ::GetBufferedPaintTargetDC(m_hPaintBuffer); 890 | } 891 | 892 | HDC GetPaintDC() const 893 | { 894 | ATLASSERT(m_hPaintBuffer != NULL); 895 | return ::GetBufferedPaintDC(m_hPaintBuffer); 896 | } 897 | 898 | HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const 899 | { 900 | ATLASSERT(m_hPaintBuffer != NULL); 901 | return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow); 902 | } 903 | 904 | HRESULT Clear(const RECT* pRect = NULL) 905 | { 906 | ATLASSERT(m_hPaintBuffer != NULL); 907 | return ::BufferedPaintClear(m_hPaintBuffer, pRect); 908 | } 909 | 910 | HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL) 911 | { 912 | ATLASSERT(m_hPaintBuffer != NULL); 913 | return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha); 914 | } 915 | 916 | HRESULT MakeOpaque(const RECT* pRect = NULL) 917 | { 918 | ATLASSERT(m_hPaintBuffer != NULL); 919 | return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255); 920 | } 921 | }; 922 | 923 | 924 | /////////////////////////////////////////////////////////////////////////////// 925 | // CBufferedPaintImpl - provides buffered paint for any window 926 | 927 | template 928 | class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase 929 | { 930 | public: 931 | CBufferedPaint m_BufferedPaint; 932 | BP_BUFFERFORMAT m_dwFormat; 933 | BP_PAINTPARAMS m_PaintParams; 934 | 935 | CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB) 936 | { 937 | memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); 938 | m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); 939 | } 940 | 941 | // Message map and handlers 942 | BEGIN_MSG_MAP(CBufferedPaintImpl) 943 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 944 | MESSAGE_HANDLER(WM_PAINT, OnPaint) 945 | MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) 946 | END_MSG_MAP() 947 | 948 | LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 949 | { 950 | return 1; // no background needed 951 | } 952 | 953 | LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 954 | { 955 | T* pT = static_cast(this); 956 | if(wParam != NULL) 957 | { 958 | RECT rect = { 0 }; 959 | pT->GetClientRect(&rect); 960 | pT->DoPaint((HDC)wParam, rect); 961 | } 962 | else 963 | { 964 | CPaintDC dc(pT->m_hWnd); 965 | pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint); 966 | } 967 | 968 | return 0; 969 | } 970 | 971 | // Overrideables 972 | void DoBufferedPaint(CDCHandle dc, RECT& rect) 973 | { 974 | HDC hDCPaint = NULL; 975 | if(IsBufferedPaintSupported()) 976 | m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); 977 | 978 | T* pT = static_cast(this); 979 | if(hDCPaint != NULL) 980 | pT->DoPaint(hDCPaint, rect); 981 | else 982 | pT->DoPaint(dc.m_hDC, rect); 983 | 984 | if(IsBufferedPaintSupported()) 985 | m_BufferedPaint.End(); 986 | } 987 | 988 | void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/) 989 | { 990 | // must be implemented in a derived class 991 | ATLASSERT(FALSE); 992 | } 993 | }; 994 | 995 | 996 | /////////////////////////////////////////////////////////////////////////////// 997 | // CBufferedPaintWindowImpl - implements a window that uses buffered paint 998 | 999 | template 1000 | class ATL_NO_VTABLE CBufferedPaintWindowImpl : 1001 | public ATL::CWindowImpl, 1002 | public CBufferedPaintImpl< T > 1003 | { 1004 | public: 1005 | BEGIN_MSG_MAP(CBufferedPaintWindowImpl) 1006 | CHAIN_MSG_MAP(CBufferedPaintImpl< T >) 1007 | END_MSG_MAP() 1008 | }; 1009 | 1010 | 1011 | /////////////////////////////////////////////////////////////////////////////// 1012 | // CBufferedAnimation - support for buffered animation 1013 | 1014 | class CBufferedAnimation 1015 | { 1016 | public: 1017 | HANIMATIONBUFFER m_hAnimationBuffer; 1018 | 1019 | CBufferedAnimation() : m_hAnimationBuffer(NULL) 1020 | { } 1021 | 1022 | ~CBufferedAnimation() 1023 | { 1024 | ATLVERIFY(SUCCEEDED(End())); 1025 | } 1026 | 1027 | bool IsNull() const 1028 | { 1029 | return (m_hAnimationBuffer == NULL); 1030 | } 1031 | 1032 | HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo) 1033 | { 1034 | ATLASSERT(m_hAnimationBuffer == NULL); 1035 | m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); 1036 | return m_hAnimationBuffer; 1037 | } 1038 | 1039 | HRESULT End(BOOL bUpdate = TRUE) 1040 | { 1041 | HRESULT hRet = S_FALSE; 1042 | if(m_hAnimationBuffer != NULL) 1043 | { 1044 | hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate); 1045 | m_hAnimationBuffer = NULL; 1046 | } 1047 | return hRet; 1048 | } 1049 | 1050 | static bool IsRendering(HWND hWnd, HDC hDC) 1051 | { 1052 | return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE); 1053 | } 1054 | }; 1055 | 1056 | 1057 | /////////////////////////////////////////////////////////////////////////////// 1058 | // CBufferedAnimationImpl - provides buffered animation support for any window 1059 | 1060 | // Note: You can either use m_State and m_NewState to store the state information 1061 | // for the animation change, or map your state to those data members. DoPaint() 1062 | // should only rely on the state information that is passed to it. 1063 | 1064 | template 1065 | class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase 1066 | { 1067 | public: 1068 | BP_BUFFERFORMAT m_dwFormat; 1069 | BP_PAINTPARAMS m_PaintParams; 1070 | BP_ANIMATIONPARAMS m_AnimationParams; 1071 | 1072 | TState m_State; 1073 | TState m_NewState; 1074 | 1075 | CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB) 1076 | { 1077 | memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); 1078 | m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); 1079 | 1080 | memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS)); 1081 | m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS); 1082 | m_AnimationParams.style = BPAS_LINEAR; 1083 | m_AnimationParams.dwDuration = 500; 1084 | 1085 | T* pT = static_cast(this); 1086 | pT->SetState(InitialState); 1087 | pT->SetNewState(InitialState); 1088 | } 1089 | 1090 | DWORD GetDuration() const 1091 | { 1092 | return m_AnimationParams.dwDuration; 1093 | } 1094 | 1095 | void SetDuration(DWORD dwDuration) 1096 | { 1097 | m_AnimationParams.dwDuration = dwDuration; 1098 | } 1099 | 1100 | void DoAnimation(TState NewState, const RECT* pRect = NULL) 1101 | { 1102 | T* pT = static_cast(this); 1103 | pT->SetNewState(NewState); 1104 | 1105 | pT->InvalidateRect(pRect, FALSE); 1106 | pT->UpdateWindow(); 1107 | 1108 | pT->SetState(NewState); 1109 | } 1110 | 1111 | // Message map and handlers 1112 | BEGIN_MSG_MAP(CBufferedAnimationImpl) 1113 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 1114 | MESSAGE_HANDLER(WM_PAINT, OnPaint) 1115 | MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) 1116 | END_MSG_MAP() 1117 | 1118 | LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 1119 | { 1120 | return 1; // no background needed 1121 | } 1122 | 1123 | LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 1124 | { 1125 | T* pT = static_cast(this); 1126 | if(wParam != NULL) 1127 | { 1128 | RECT rect = { 0 }; 1129 | pT->GetClientRect(&rect); 1130 | pT->DoPaint((HDC)wParam, rect, m_NewState); 1131 | } 1132 | else 1133 | { 1134 | CPaintDC dc(pT->m_hWnd); 1135 | pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint); 1136 | } 1137 | 1138 | return 0; 1139 | } 1140 | 1141 | // Overrideables 1142 | void SetState(TState State) 1143 | { 1144 | m_State = State; 1145 | } 1146 | 1147 | void SetNewState(TState State) 1148 | { 1149 | m_NewState = State; 1150 | } 1151 | 1152 | bool AreStatesEqual() const 1153 | { 1154 | return (m_State == m_NewState); 1155 | } 1156 | 1157 | void DoAnimationPaint(CDCHandle dc, RECT& rect) 1158 | { 1159 | T* pT = static_cast(this); 1160 | if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc)) 1161 | return; 1162 | 1163 | DWORD dwDurationSave = m_AnimationParams.dwDuration; 1164 | if(pT->AreStatesEqual()) 1165 | m_AnimationParams.dwDuration = 0; 1166 | 1167 | HDC hdcFrom = NULL, hdcTo = NULL; 1168 | CBufferedAnimation ba; 1169 | if(IsBufferedPaintSupported()) 1170 | ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo); 1171 | 1172 | if(!ba.IsNull()) 1173 | { 1174 | if(hdcFrom != NULL) 1175 | pT->DoPaint(hdcFrom, rect, m_State); 1176 | 1177 | if (hdcTo != NULL) 1178 | pT->DoPaint(hdcTo, rect, m_NewState); 1179 | } 1180 | else 1181 | { 1182 | pT->DoPaint(dc.m_hDC, rect, m_NewState); 1183 | } 1184 | 1185 | m_AnimationParams.dwDuration = dwDurationSave; 1186 | } 1187 | 1188 | void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/) 1189 | { 1190 | // must be implemented in a derived class 1191 | ATLASSERT(FALSE); 1192 | } 1193 | }; 1194 | 1195 | 1196 | /////////////////////////////////////////////////////////////////////////////// 1197 | // CBufferedAnimationWindowImpl - implements a window that uses buffered animation 1198 | 1199 | template 1200 | class ATL_NO_VTABLE CBufferedAnimationWindowImpl : 1201 | public ATL::CWindowImpl, 1202 | public CBufferedAnimationImpl< T, TState > 1203 | { 1204 | public: 1205 | CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState) 1206 | { } 1207 | 1208 | typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation; 1209 | BEGIN_MSG_MAP(CBufferedAnimationWindowImpl) 1210 | CHAIN_MSG_MAP(_baseBufferedAnimation) 1211 | END_MSG_MAP() 1212 | }; 1213 | 1214 | #endif // _WTL_NEW_UXTHEME 1215 | 1216 | }; // namespace WTL 1217 | 1218 | #endif // __ATLTHEME_H__ 1219 | --------------------------------------------------------------------------------